proxygen
NetOps.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2013-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <folly/net/NetOps.h>
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 
22 #include <cstddef>
23 
24 #include <folly/Portability.h>
26 
27 #if _WIN32
28 #include <event2/util.h> // @manual
29 
30 #include <MSWSock.h> // @manual
31 
32 #include <folly/ScopeGuard.h>
33 #endif
34 
35 namespace folly {
36 namespace netops {
37 
38 namespace {
39 #if _WIN32
40 // WSA has to be explicitly initialized.
41 static struct WinSockInit {
42  WinSockInit() {
43  WSADATA dat;
44  WSAStartup(MAKEWORD(2, 2), &dat);
45  }
46  ~WinSockInit() {
47  WSACleanup();
48  }
49 } winsockInit;
50 
51 int translate_wsa_error(int wsaErr) {
52  switch (wsaErr) {
53  case WSAEWOULDBLOCK:
54  return EAGAIN;
55  default:
56  return wsaErr;
57  }
58 }
59 #endif
60 
61 template <class R, class F, class... Args>
62 static R wrapSocketFunction(F f, NetworkSocket s, Args... args) {
63  R ret = f(s.data, args...);
64 #if _WIN32
65  errno = translate_wsa_error(WSAGetLastError());
66 #endif
67  return ret;
68 }
69 } // namespace
70 
71 NetworkSocket accept(NetworkSocket s, sockaddr* addr, socklen_t* addrlen) {
72  return NetworkSocket(wrapSocketFunction<NetworkSocket::native_handle_type>(
73  ::accept, s, addr, addrlen));
74 }
75 
76 int bind(NetworkSocket s, const sockaddr* name, socklen_t namelen) {
77  if (kIsWindows && name->sa_family == AF_UNIX) {
78  // Windows added support for AF_UNIX sockets, but didn't add
79  // support for autobind sockets, so detect requests for autobind
80  // sockets and treat them as invalid. (otherwise they don't trigger
81  // an error, but also don't actually work)
82  if (name->sa_data[0] == '\0') {
83  errno = EINVAL;
84  return -1;
85  }
86  }
87  return wrapSocketFunction<int>(::bind, s, name, namelen);
88 }
89 
92 }
93 
94 int connect(NetworkSocket s, const sockaddr* name, socklen_t namelen) {
95  auto r = wrapSocketFunction<int>(::connect, s, name, namelen);
96 #if _WIN32
97  if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) {
98  errno = EINPROGRESS;
99  }
100 #endif
101  return r;
102 }
103 
104 int getpeername(NetworkSocket s, sockaddr* name, socklen_t* namelen) {
105  return wrapSocketFunction<int>(::getpeername, s, name, namelen);
106 }
107 
108 int getsockname(NetworkSocket s, sockaddr* name, socklen_t* namelen) {
109  return wrapSocketFunction<int>(::getsockname, s, name, namelen);
110 }
111 
114  int level,
115  int optname,
116  void* optval,
117  socklen_t* optlen) {
118  auto ret = wrapSocketFunction<int>(
119  ::getsockopt, s, level, optname, (char*)optval, optlen);
120 #if _WIN32
121  if (optname == TCP_NODELAY && *optlen == 1) {
122  // Windows is weird about this value, and documents it as a
123  // BOOL (ie. int) but expects the variable to be bool (1-byte),
124  // so we get to adapt the interface to work that way.
125  *(int*)optval = *(uint8_t*)optval;
126  *optlen = sizeof(int);
127  }
128 #endif
129  return ret;
130 }
131 
132 int inet_aton(const char* cp, in_addr* inp) {
133  inp->s_addr = inet_addr(cp);
134  return inp->s_addr == INADDR_NONE ? 0 : 1;
135 }
136 
137 int listen(NetworkSocket s, int backlog) {
138  return wrapSocketFunction<int>(::listen, s, backlog);
139 }
140 
141 int poll(PollDescriptor fds[], nfds_t nfds, int timeout) {
142  // Make sure that PollDescriptor is byte-for-byte identical to pollfd,
143  // so we don't need extra allocations just for the safety of this shim.
144  static_assert(
145  alignof(PollDescriptor) == alignof(pollfd),
146  "PollDescriptor is misaligned");
147  static_assert(
148  sizeof(PollDescriptor) == sizeof(pollfd),
149  "PollDescriptor is the wrong size");
150  static_assert(
151  offsetof(PollDescriptor, fd) == offsetof(pollfd, fd),
152  "PollDescriptor.fd is at the wrong place");
153  static_assert(
154  sizeof(decltype(PollDescriptor().fd)) == sizeof(decltype(pollfd().fd)),
155  "PollDescriptor.fd is the wrong size");
156  static_assert(
157  offsetof(PollDescriptor, events) == offsetof(pollfd, events),
158  "PollDescriptor.events is at the wrong place");
159  static_assert(
160  sizeof(decltype(PollDescriptor().events)) ==
161  sizeof(decltype(pollfd().events)),
162  "PollDescriptor.events is the wrong size");
163  static_assert(
164  offsetof(PollDescriptor, revents) == offsetof(pollfd, revents),
165  "PollDescriptor.revents is at the wrong place");
166  static_assert(
167  sizeof(decltype(PollDescriptor().revents)) ==
168  sizeof(decltype(pollfd().revents)),
169  "PollDescriptor.revents is the wrong size");
170 
171  // Pun it through
172  pollfd* files = reinterpret_cast<pollfd*>(reinterpret_cast<void*>(fds));
173 #if _WIN32
174  return ::WSAPoll(files, (ULONG)nfds, timeout);
175 #else
176  return ::poll(files, nfds, timeout);
177 #endif
178 }
179 
180 ssize_t recv(NetworkSocket s, void* buf, size_t len, int flags) {
181 #if _WIN32
182  if ((flags & MSG_DONTWAIT) == MSG_DONTWAIT) {
183  flags &= ~MSG_DONTWAIT;
184 
185  u_long pendingRead = 0;
186  if (ioctlsocket(s.data, FIONREAD, &pendingRead)) {
187  errno = translate_wsa_error(WSAGetLastError());
188  return -1;
189  }
190 
191  fd_set readSet;
192  FD_ZERO(&readSet);
193  FD_SET(s.data, &readSet);
194  timeval timeout{0, 0};
195  auto ret = select(1, &readSet, nullptr, nullptr, &timeout);
196  if (ret == 0) {
197  errno = EWOULDBLOCK;
198  return -1;
199  }
200  }
201  return wrapSocketFunction<ssize_t>(::recv, s, (char*)buf, (int)len, flags);
202 #else
203  return wrapSocketFunction<ssize_t>(::recv, s, buf, len, flags);
204 #endif
205 }
206 
207 ssize_t recvfrom(
209  void* buf,
210  size_t len,
211  int flags,
212  sockaddr* from,
213  socklen_t* fromlen) {
214 #if _WIN32
215  if ((flags & MSG_TRUNC) == MSG_TRUNC) {
216  SOCKET h = s.data;
217 
218  WSABUF wBuf{};
219  wBuf.buf = (CHAR*)buf;
220  wBuf.len = (ULONG)len;
221  WSAMSG wMsg{};
222  wMsg.dwBufferCount = 1;
223  wMsg.lpBuffers = &wBuf;
224  wMsg.name = from;
225  if (fromlen != nullptr) {
226  wMsg.namelen = *fromlen;
227  }
228 
229  // WSARecvMsg is an extension, so we don't get
230  // the convenience of being able to call it directly, even though
231  // WSASendMsg is part of the normal API -_-...
232  LPFN_WSARECVMSG WSARecvMsg;
233  GUID WSARecgMsg_GUID = WSAID_WSARECVMSG;
234  DWORD recMsgBytes;
235  WSAIoctl(
236  h,
237  SIO_GET_EXTENSION_FUNCTION_POINTER,
238  &WSARecgMsg_GUID,
239  sizeof(WSARecgMsg_GUID),
240  &WSARecvMsg,
241  sizeof(WSARecvMsg),
242  &recMsgBytes,
243  nullptr,
244  nullptr);
245 
246  DWORD bytesReceived;
247  int res = WSARecvMsg(h, &wMsg, &bytesReceived, nullptr, nullptr);
248  errno = translate_wsa_error(WSAGetLastError());
249  if (res == 0) {
250  return bytesReceived;
251  }
252  if (fromlen != nullptr) {
253  *fromlen = wMsg.namelen;
254  }
255  if ((wMsg.dwFlags & MSG_TRUNC) == MSG_TRUNC) {
256  return wBuf.len + 1;
257  }
258  return -1;
259  }
260  return wrapSocketFunction<ssize_t>(
261  ::recvfrom, s, (char*)buf, (int)len, flags, from, fromlen);
262 #else
263  return wrapSocketFunction<ssize_t>(
264  ::recvfrom, s, buf, len, flags, from, fromlen);
265 #endif
266 }
267 
268 ssize_t recvmsg(NetworkSocket s, msghdr* message, int flags) {
269 #if _WIN32
270  (void)flags;
271  SOCKET h = s.data;
272 
273  // Don't currently support the name translation.
274  if (message->msg_name != nullptr || message->msg_namelen != 0) {
275  return (ssize_t)-1;
276  }
277  WSAMSG msg;
278  msg.name = nullptr;
279  msg.namelen = 0;
280  msg.Control.buf = (CHAR*)message->msg_control;
281  msg.Control.len = (ULONG)message->msg_controllen;
282  msg.dwFlags = 0;
283  msg.dwBufferCount = (DWORD)message->msg_iovlen;
284  msg.lpBuffers = new WSABUF[message->msg_iovlen];
285  SCOPE_EXIT {
286  delete[] msg.lpBuffers;
287  };
288  for (size_t i = 0; i < message->msg_iovlen; i++) {
289  msg.lpBuffers[i].buf = (CHAR*)message->msg_iov[i].iov_base;
290  msg.lpBuffers[i].len = (ULONG)message->msg_iov[i].iov_len;
291  }
292 
293  // WSARecvMsg is an extension, so we don't get
294  // the convenience of being able to call it directly, even though
295  // WSASendMsg is part of the normal API -_-...
296  LPFN_WSARECVMSG WSARecvMsg;
297  GUID WSARecgMsg_GUID = WSAID_WSARECVMSG;
298  DWORD recMsgBytes;
299  WSAIoctl(
300  h,
301  SIO_GET_EXTENSION_FUNCTION_POINTER,
302  &WSARecgMsg_GUID,
303  sizeof(WSARecgMsg_GUID),
304  &WSARecvMsg,
305  sizeof(WSARecvMsg),
306  &recMsgBytes,
307  nullptr,
308  nullptr);
309 
310  DWORD bytesReceived;
311  int res = WSARecvMsg(h, &msg, &bytesReceived, nullptr, nullptr);
312  errno = translate_wsa_error(WSAGetLastError());
313  return res == 0 ? (ssize_t)bytesReceived : -1;
314 #else
315  return wrapSocketFunction<ssize_t>(::recvmsg, s, message, flags);
316 #endif
317 }
318 
319 ssize_t send(NetworkSocket s, const void* buf, size_t len, int flags) {
320 #if _WIN32
321  return wrapSocketFunction<ssize_t>(
322  ::send, s, (const char*)buf, (int)len, flags);
323 #else
324  return wrapSocketFunction<ssize_t>(::send, s, buf, len, flags);
325 #endif
326 }
327 
328 ssize_t sendmsg(NetworkSocket socket, const msghdr* message, int flags) {
329 #if _WIN32
330  (void)flags;
331  SOCKET h = socket.data;
332 
333  // Unfortunately, WSASendMsg requires the socket to have been opened
334  // as either SOCK_DGRAM or SOCK_RAW, but sendmsg has no such requirement,
335  // so we have to implement it based on send instead :(
336  ssize_t bytesSent = 0;
337  for (size_t i = 0; i < message->msg_iovlen; i++) {
338  int r = -1;
339  if (message->msg_name != nullptr) {
340  r = ::sendto(
341  h,
342  (const char*)message->msg_iov[i].iov_base,
343  (int)message->msg_iov[i].iov_len,
344  message->msg_flags,
345  (const sockaddr*)message->msg_name,
346  (int)message->msg_namelen);
347  } else {
348  r = ::send(
349  h,
350  (const char*)message->msg_iov[i].iov_base,
351  (int)message->msg_iov[i].iov_len,
352  message->msg_flags);
353  }
354  if (r == -1 || size_t(r) != message->msg_iov[i].iov_len) {
355  errno = translate_wsa_error(WSAGetLastError());
356  if (WSAGetLastError() == WSAEWOULDBLOCK && bytesSent > 0) {
357  return bytesSent;
358  }
359  return -1;
360  }
361  bytesSent += r;
362  }
363  return bytesSent;
364 #else
365  return wrapSocketFunction<ssize_t>(::sendmsg, socket, message, flags);
366 #endif
367 }
368 
369 ssize_t sendto(
371  const void* buf,
372  size_t len,
373  int flags,
374  const sockaddr* to,
375  socklen_t tolen) {
376 #if _WIN32
377  return wrapSocketFunction<ssize_t>(
378  ::sendto, s, (const char*)buf, (int)len, flags, to, (int)tolen);
379 #else
380  return wrapSocketFunction<ssize_t>(::sendto, s, buf, len, flags, to, tolen);
381 #endif
382 }
383 
386  int level,
387  int optname,
388  const void* optval,
389  socklen_t optlen) {
390 #if _WIN32
391  if (optname == SO_REUSEADDR) {
392  // We don't have an equivelent to the Linux & OSX meaning of this
393  // on Windows, so ignore it.
394  return 0;
395  } else if (optname == SO_REUSEPORT) {
396  // Windows's SO_REUSEADDR option is closer to SO_REUSEPORT than
397  // it is to the Linux & OSX meaning of SO_REUSEADDR.
398  return -1;
399  }
400  return wrapSocketFunction<int>(
401  ::setsockopt, s, level, optname, (char*)optval, optlen);
402 #else
403  return wrapSocketFunction<int>(
404  ::setsockopt, s, level, optname, optval, optlen);
405 #endif
406 }
407 
408 int shutdown(NetworkSocket s, int how) {
409  return wrapSocketFunction<int>(::shutdown, s, how);
410 }
411 
412 NetworkSocket socket(int af, int type, int protocol) {
413  return NetworkSocket(::socket(af, type, protocol));
414 }
415 
416 int socketpair(int domain, int type, int protocol, NetworkSocket sv[2]) {
417 #if _WIN32
418  if (domain != PF_UNIX || type != SOCK_STREAM || protocol != 0) {
419  return -1;
420  }
421  intptr_t pair[2];
422  auto r = evutil_socketpair(AF_INET, type, protocol, pair);
423  if (r == -1) {
424  return r;
425  }
426  sv[0] = NetworkSocket(static_cast<SOCKET>(pair[0]));
427  sv[1] = NetworkSocket(static_cast<SOCKET>(pair[1]));
428  return r;
429 #else
430  int pair[2];
431  auto r = ::socketpair(domain, type, protocol, pair);
432  if (r == -1) {
433  return r;
434  }
435  sv[0] = NetworkSocket(pair[0]);
436  sv[1] = NetworkSocket(pair[1]);
437  return r;
438 #endif
439 }
440 
442 #if _WIN32
443  u_long nonBlockingEnabled = 1;
444  return ioctlsocket(s.data, FIONBIO, &nonBlockingEnabled);
445 #else
446  int flags = fcntl(s.data, F_GETFL, 0);
447  if (flags == -1) {
448  return -1;
449  }
450  return fcntl(s.data, F_SETFL, flags | O_NONBLOCK);
451 #endif
452 }
453 
455 #if _WIN32
456  if (SetHandleInformation((HANDLE)s.data, HANDLE_FLAG_INHERIT, 0)) {
457  return 0;
458  }
459  return -1;
460 #else
461  return fcntl(s.data, F_SETFD, FD_CLOEXEC);
462 #endif
463 }
464 } // namespace netops
465 } // namespace folly
ssize_t recvfrom(NetworkSocket s, void *buf, size_t len, int flags, sockaddr *from, socklen_t *fromlen)
Definition: NetOps.cpp:207
Definition: test.c:42
*than *hazptr_holder h
Definition: Hazptr.h:116
auto f
flags
Definition: http_parser.h:127
int connect(NetworkSocket s, const sockaddr *name, socklen_t namelen)
Definition: NetOps.cpp:94
ssize_t sendmsg(NetworkSocket socket, const msghdr *message, int flags)
Definition: NetOps.cpp:328
int inet_aton(const char *cp, in_addr *inp)
Definition: NetOps.cpp:132
int setsockopt(NetworkSocket s, int level, int optname, const void *optval, socklen_t optlen)
Definition: NetOps.cpp:384
PskType type
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
const char * name
Definition: http_parser.c:437
int getsockname(NetworkSocket s, sockaddr *name, socklen_t *namelen)
Definition: NetOps.cpp:108
int shutdown(NetworkSocket s, int how)
Definition: NetOps.cpp:408
ssize_t sendto(NetworkSocket s, const void *buf, size_t len, int flags, const sockaddr *to, socklen_t tolen)
Definition: NetOps.cpp:369
std::enable_if< detail::is_chrono_conversion< Tgt, Src >::value, Tgt >::type to(const Src &value)
Definition: Conv.h:677
int getsockopt(NetworkSocket s, int level, int optname, void *optval, socklen_t *optlen)
Definition: NetOps.cpp:112
std::string message
Definition: SPDYCodec.cpp:133
ssize_t send(NetworkSocket s, const void *buf, size_t len, int flags)
Definition: NetOps.cpp:319
NetworkSocket socket(int af, int type, int protocol)
Definition: NetOps.cpp:412
int listen(NetworkSocket s, int backlog)
Definition: NetOps.cpp:137
PUSHMI_INLINE_VAR constexpr struct folly::pushmi::operators::from_fn from
ssize_t recvmsg(NetworkSocket s, msghdr *message, int flags)
Definition: NetOps.cpp:268
int set_socket_non_blocking(NetworkSocket s)
Definition: NetOps.cpp:441
int poll(PollDescriptor fds[], nfds_t nfds, int timeout)
Definition: NetOps.cpp:141
int bind(NetworkSocket s, const sockaddr *name, socklen_t namelen)
Definition: NetOps.cpp:76
static set< string > s
int getpeername(NetworkSocket s, sockaddr *name, socklen_t *namelen)
Definition: NetOps.cpp:104
Definition: Traits.h:577
constexpr auto kIsWindows
Definition: Portability.h:367
int set_socket_close_on_exec(NetworkSocket s)
Definition: NetOps.cpp:454
#define SO_REUSEPORT
ssize_t recv(NetworkSocket s, void *buf, size_t len, int flags)
Definition: NetOps.cpp:180
int close(NetworkSocket s)
Definition: NetOps.cpp:90
ThreadPoolListHook * addr
native_handle_type data
Definition: NetworkSocket.h:39
int socketpair(int domain, int type, int protocol, NetworkSocket sv[2])
Definition: NetOps.cpp:416
NetworkSocket accept(NetworkSocket s, sockaddr *addr, socklen_t *addrlen)
Definition: NetOps.cpp:71