/src/muduo/muduo/net/SocketsOps.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2010, Shuo Chen. All rights reserved. |
2 | | // http://code.google.com/p/muduo/ |
3 | | // |
4 | | // Use of this source code is governed by a BSD-style license |
5 | | // that can be found in the License file. |
6 | | |
7 | | // Author: Shuo Chen (chenshuo at chenshuo dot com) |
8 | | |
9 | | #include "muduo/net/SocketsOps.h" |
10 | | |
11 | | #include "muduo/base/Logging.h" |
12 | | #include "muduo/base/Types.h" |
13 | | #include "muduo/net/Endian.h" |
14 | | |
15 | | #include <errno.h> |
16 | | #include <fcntl.h> |
17 | | #include <stdio.h> // snprintf |
18 | | #include <sys/socket.h> |
19 | | #include <sys/uio.h> // readv |
20 | | #include <unistd.h> |
21 | | |
22 | | using namespace muduo; |
23 | | using namespace muduo::net; |
24 | | |
25 | | namespace |
26 | | { |
27 | | |
28 | | typedef struct sockaddr SA; |
29 | | |
30 | | |
31 | | #if VALGRIND || defined (NO_ACCEPT4) |
32 | | void setNonBlockAndCloseOnExec(int sockfd) |
33 | | { |
34 | | // non-block |
35 | | int flags = ::fcntl(sockfd, F_GETFL, 0); |
36 | | flags |= O_NONBLOCK; |
37 | | int ret = ::fcntl(sockfd, F_SETFL, flags); |
38 | | // FIXME check |
39 | | |
40 | | // close-on-exec |
41 | | flags = ::fcntl(sockfd, F_GETFD, 0); |
42 | | flags |= FD_CLOEXEC; |
43 | | ret = ::fcntl(sockfd, F_SETFD, flags); |
44 | | // FIXME check |
45 | | |
46 | | (void)ret; |
47 | | } |
48 | | #endif |
49 | | |
50 | | } // namespace |
51 | | |
52 | | const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in6* addr) |
53 | 0 | { |
54 | 0 | return static_cast<const struct sockaddr*>(implicit_cast<const void*>(addr)); |
55 | 0 | } |
56 | | |
57 | | struct sockaddr* sockets::sockaddr_cast(struct sockaddr_in6* addr) |
58 | 0 | { |
59 | 0 | return static_cast<struct sockaddr*>(implicit_cast<void*>(addr)); |
60 | 0 | } |
61 | | |
62 | | const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in* addr) |
63 | 0 | { |
64 | 0 | return static_cast<const struct sockaddr*>(implicit_cast<const void*>(addr)); |
65 | 0 | } |
66 | | |
67 | | const struct sockaddr_in* sockets::sockaddr_in_cast(const struct sockaddr* addr) |
68 | 0 | { |
69 | 0 | return static_cast<const struct sockaddr_in*>(implicit_cast<const void*>(addr)); |
70 | 0 | } |
71 | | |
72 | | const struct sockaddr_in6* sockets::sockaddr_in6_cast(const struct sockaddr* addr) |
73 | 0 | { |
74 | 0 | return static_cast<const struct sockaddr_in6*>(implicit_cast<const void*>(addr)); |
75 | 0 | } |
76 | | |
77 | | int sockets::createNonblockingOrDie(sa_family_t family) |
78 | 0 | { |
79 | | #if VALGRIND |
80 | | int sockfd = ::socket(family, SOCK_STREAM, IPPROTO_TCP); |
81 | | if (sockfd < 0) |
82 | | { |
83 | | LOG_SYSFATAL << "sockets::createNonblockingOrDie"; |
84 | | } |
85 | | |
86 | | setNonBlockAndCloseOnExec(sockfd); |
87 | | #else |
88 | 0 | int sockfd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); |
89 | 0 | if (sockfd < 0) |
90 | 0 | { |
91 | 0 | LOG_SYSFATAL << "sockets::createNonblockingOrDie"; |
92 | 0 | } |
93 | 0 | #endif |
94 | 0 | return sockfd; |
95 | 0 | } |
96 | | |
97 | | void sockets::bindOrDie(int sockfd, const struct sockaddr* addr) |
98 | 0 | { |
99 | 0 | int ret = ::bind(sockfd, addr, static_cast<socklen_t>(sizeof(struct sockaddr_in6))); |
100 | 0 | if (ret < 0) |
101 | 0 | { |
102 | 0 | LOG_SYSFATAL << "sockets::bindOrDie"; |
103 | 0 | } |
104 | 0 | } |
105 | | |
106 | | void sockets::listenOrDie(int sockfd) |
107 | 0 | { |
108 | 0 | int ret = ::listen(sockfd, SOMAXCONN); |
109 | 0 | if (ret < 0) |
110 | 0 | { |
111 | 0 | LOG_SYSFATAL << "sockets::listenOrDie"; |
112 | 0 | } |
113 | 0 | } |
114 | | |
115 | | int sockets::accept(int sockfd, struct sockaddr_in6* addr) |
116 | 0 | { |
117 | 0 | socklen_t addrlen = static_cast<socklen_t>(sizeof *addr); |
118 | | #if VALGRIND || defined (NO_ACCEPT4) |
119 | | int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); |
120 | | setNonBlockAndCloseOnExec(connfd); |
121 | | #else |
122 | 0 | int connfd = ::accept4(sockfd, sockaddr_cast(addr), |
123 | 0 | &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); |
124 | 0 | #endif |
125 | 0 | if (connfd < 0) |
126 | 0 | { |
127 | 0 | int savedErrno = errno; |
128 | 0 | LOG_SYSERR << "Socket::accept"; |
129 | 0 | switch (savedErrno) |
130 | 0 | { |
131 | 0 | case EAGAIN: |
132 | 0 | case ECONNABORTED: |
133 | 0 | case EINTR: |
134 | 0 | case EPROTO: // ??? |
135 | 0 | case EPERM: |
136 | 0 | case EMFILE: // per-process lmit of open file desctiptor ??? |
137 | | // expected errors |
138 | 0 | errno = savedErrno; |
139 | 0 | break; |
140 | 0 | case EBADF: |
141 | 0 | case EFAULT: |
142 | 0 | case EINVAL: |
143 | 0 | case ENFILE: |
144 | 0 | case ENOBUFS: |
145 | 0 | case ENOMEM: |
146 | 0 | case ENOTSOCK: |
147 | 0 | case EOPNOTSUPP: |
148 | | // unexpected errors |
149 | 0 | LOG_FATAL << "unexpected error of ::accept " << savedErrno; |
150 | 0 | break; |
151 | 0 | default: |
152 | 0 | LOG_FATAL << "unknown error of ::accept " << savedErrno; |
153 | 0 | break; |
154 | 0 | } |
155 | 0 | } |
156 | 0 | return connfd; |
157 | 0 | } |
158 | | |
159 | | int sockets::connect(int sockfd, const struct sockaddr* addr) |
160 | 0 | { |
161 | 0 | return ::connect(sockfd, addr, static_cast<socklen_t>(sizeof(struct sockaddr_in6))); |
162 | 0 | } |
163 | | |
164 | | ssize_t sockets::read(int sockfd, void *buf, size_t count) |
165 | 0 | { |
166 | 0 | return ::read(sockfd, buf, count); |
167 | 0 | } |
168 | | |
169 | | ssize_t sockets::readv(int sockfd, const struct iovec *iov, int iovcnt) |
170 | 0 | { |
171 | 0 | return ::readv(sockfd, iov, iovcnt); |
172 | 0 | } |
173 | | |
174 | | ssize_t sockets::write(int sockfd, const void *buf, size_t count) |
175 | 0 | { |
176 | 0 | return ::write(sockfd, buf, count); |
177 | 0 | } |
178 | | |
179 | | void sockets::close(int sockfd) |
180 | 0 | { |
181 | 0 | if (::close(sockfd) < 0) |
182 | 0 | { |
183 | 0 | LOG_SYSERR << "sockets::close"; |
184 | 0 | } |
185 | 0 | } |
186 | | |
187 | | void sockets::shutdownWrite(int sockfd) |
188 | 0 | { |
189 | 0 | if (::shutdown(sockfd, SHUT_WR) < 0) |
190 | 0 | { |
191 | 0 | LOG_SYSERR << "sockets::shutdownWrite"; |
192 | 0 | } |
193 | 0 | } |
194 | | |
195 | | void sockets::toIpPort(char* buf, size_t size, |
196 | | const struct sockaddr* addr) |
197 | 0 | { |
198 | 0 | if (addr->sa_family == AF_INET6) |
199 | 0 | { |
200 | 0 | buf[0] = '['; |
201 | 0 | toIp(buf+1, size-1, addr); |
202 | 0 | size_t end = ::strlen(buf); |
203 | 0 | const struct sockaddr_in6* addr6 = sockaddr_in6_cast(addr); |
204 | 0 | uint16_t port = sockets::networkToHost16(addr6->sin6_port); |
205 | 0 | assert(size > end); |
206 | 0 | snprintf(buf+end, size-end, "]:%u", port); |
207 | 0 | return; |
208 | 0 | } |
209 | 0 | toIp(buf, size, addr); |
210 | 0 | size_t end = ::strlen(buf); |
211 | 0 | const struct sockaddr_in* addr4 = sockaddr_in_cast(addr); |
212 | 0 | uint16_t port = sockets::networkToHost16(addr4->sin_port); |
213 | 0 | assert(size > end); |
214 | 0 | snprintf(buf+end, size-end, ":%u", port); |
215 | 0 | } |
216 | | |
217 | | void sockets::toIp(char* buf, size_t size, |
218 | | const struct sockaddr* addr) |
219 | 0 | { |
220 | 0 | if (addr->sa_family == AF_INET) |
221 | 0 | { |
222 | 0 | assert(size >= INET_ADDRSTRLEN); |
223 | 0 | const struct sockaddr_in* addr4 = sockaddr_in_cast(addr); |
224 | 0 | ::inet_ntop(AF_INET, &addr4->sin_addr, buf, static_cast<socklen_t>(size)); |
225 | 0 | } |
226 | 0 | else if (addr->sa_family == AF_INET6) |
227 | 0 | { |
228 | 0 | assert(size >= INET6_ADDRSTRLEN); |
229 | 0 | const struct sockaddr_in6* addr6 = sockaddr_in6_cast(addr); |
230 | 0 | ::inet_ntop(AF_INET6, &addr6->sin6_addr, buf, static_cast<socklen_t>(size)); |
231 | 0 | } |
232 | 0 | } |
233 | | |
234 | | void sockets::fromIpPort(const char* ip, uint16_t port, |
235 | | struct sockaddr_in* addr) |
236 | 0 | { |
237 | 0 | addr->sin_family = AF_INET; |
238 | 0 | addr->sin_port = hostToNetwork16(port); |
239 | 0 | if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) |
240 | 0 | { |
241 | 0 | LOG_SYSERR << "sockets::fromIpPort"; |
242 | 0 | } |
243 | 0 | } |
244 | | |
245 | | void sockets::fromIpPort(const char* ip, uint16_t port, |
246 | | struct sockaddr_in6* addr) |
247 | 0 | { |
248 | 0 | addr->sin6_family = AF_INET6; |
249 | 0 | addr->sin6_port = hostToNetwork16(port); |
250 | 0 | if (::inet_pton(AF_INET6, ip, &addr->sin6_addr) <= 0) |
251 | 0 | { |
252 | 0 | LOG_SYSERR << "sockets::fromIpPort"; |
253 | 0 | } |
254 | 0 | } |
255 | | |
256 | | int sockets::getSocketError(int sockfd) |
257 | 0 | { |
258 | 0 | int optval; |
259 | 0 | socklen_t optlen = static_cast<socklen_t>(sizeof optval); |
260 | |
|
261 | 0 | if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) |
262 | 0 | { |
263 | 0 | return errno; |
264 | 0 | } |
265 | 0 | else |
266 | 0 | { |
267 | 0 | return optval; |
268 | 0 | } |
269 | 0 | } |
270 | | |
271 | | struct sockaddr_in6 sockets::getLocalAddr(int sockfd) |
272 | 0 | { |
273 | 0 | struct sockaddr_in6 localaddr; |
274 | 0 | memZero(&localaddr, sizeof localaddr); |
275 | 0 | socklen_t addrlen = static_cast<socklen_t>(sizeof localaddr); |
276 | 0 | if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) |
277 | 0 | { |
278 | 0 | LOG_SYSERR << "sockets::getLocalAddr"; |
279 | 0 | } |
280 | 0 | return localaddr; |
281 | 0 | } |
282 | | |
283 | | struct sockaddr_in6 sockets::getPeerAddr(int sockfd) |
284 | 0 | { |
285 | 0 | struct sockaddr_in6 peeraddr; |
286 | 0 | memZero(&peeraddr, sizeof peeraddr); |
287 | 0 | socklen_t addrlen = static_cast<socklen_t>(sizeof peeraddr); |
288 | 0 | if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0) |
289 | 0 | { |
290 | 0 | LOG_SYSERR << "sockets::getPeerAddr"; |
291 | 0 | } |
292 | 0 | return peeraddr; |
293 | 0 | } |
294 | | |
295 | | bool sockets::isSelfConnect(int sockfd) |
296 | 0 | { |
297 | 0 | struct sockaddr_in6 localaddr = getLocalAddr(sockfd); |
298 | 0 | struct sockaddr_in6 peeraddr = getPeerAddr(sockfd); |
299 | 0 | if (localaddr.sin6_family == AF_INET) |
300 | 0 | { |
301 | 0 | const struct sockaddr_in* laddr4 = reinterpret_cast<struct sockaddr_in*>(&localaddr); |
302 | 0 | const struct sockaddr_in* raddr4 = reinterpret_cast<struct sockaddr_in*>(&peeraddr); |
303 | 0 | return laddr4->sin_port == raddr4->sin_port |
304 | 0 | && laddr4->sin_addr.s_addr == raddr4->sin_addr.s_addr; |
305 | 0 | } |
306 | 0 | else if (localaddr.sin6_family == AF_INET6) |
307 | 0 | { |
308 | 0 | return localaddr.sin6_port == peeraddr.sin6_port |
309 | 0 | && memcmp(&localaddr.sin6_addr, &peeraddr.sin6_addr, sizeof localaddr.sin6_addr) == 0; |
310 | 0 | } |
311 | 0 | else |
312 | 0 | { |
313 | 0 | return false; |
314 | 0 | } |
315 | 0 | } |
316 | | |