Apache Mesos
socket.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_OS_WINDOWS_SOCKET_HPP__
14 #define __STOUT_OS_WINDOWS_SOCKET_HPP__
15 
16 #include <glog/logging.h>
17 
18 #include <stout/abort.hpp>
19 #include <stout/try.hpp>
20 #include <stout/error.hpp>
21 #include <stout/windows.hpp> // For `WinSock2.h`.
22 
23 #include <stout/os/int_fd.hpp>
24 
25 namespace net {
26 
27 // Initialize Windows socket stack.
28 inline bool wsa_initialize()
29 {
30  // Initialize WinSock (request version 2.2).
31  WORD requestedVersion = MAKEWORD(2, 2);
32  WSADATA data;
33 
34  const int result = ::WSAStartup(requestedVersion, &data);
35  if (result != 0) {
36  const int error = ::WSAGetLastError();
37  LOG(ERROR) << "Could not initialize WinSock, error code : " << error;
38  return false;
39  }
40 
41  // Check that the WinSock version we got back is 2.2 or higher.
42  // The high-order byte specifies the minor version number.
43  if (LOBYTE(data.wVersion) < 2 ||
44  (LOBYTE(data.wVersion) == 2 && HIBYTE(data.wVersion) != 2)) {
45  LOG(ERROR) << "Incorrect WinSock version found : " << LOBYTE(data.wVersion)
46  << "." << HIBYTE(data.wVersion);
47 
48  // WinSock was initialized, we just didn't like the version, so we need to
49  // clean up.
50  if (::WSACleanup() != 0) {
51  const int error = ::WSAGetLastError();
52  LOG(ERROR) << "Could not cleanup WinSock, error code : " << error;
53  }
54 
55  return false;
56  }
57 
58  return true;
59 }
60 
61 
62 inline bool wsa_cleanup()
63 {
64  // Cleanup WinSock. Wait for any outstanding socket operations to complete
65  // before exiting. Retry for a maximum of 10 times at 1 second intervals.
66  int retriesLeft = 10;
67 
68  while (retriesLeft > 0) {
69  const int result = ::WSACleanup();
70  if (result != 0) {
71  const int error = ::WSAGetLastError();
72  // Make it idempotent.
73  if (error == WSANOTINITIALISED) {
74  return false;
75  }
76 
77  // Wait for any blocking calls to complete and retry after 1 second.
78  if (error == WSAEINPROGRESS) {
79  LOG(ERROR) << "Waiting for outstanding WinSock calls to complete.";
80  ::Sleep(1000);
81  retriesLeft--;
82  } else {
83  LOG(ERROR) << "Could not cleanup WinSock, error code : " << error;
84  return false;
85  }
86  }
87  break;
88  }
89  if (retriesLeft == 0) {
90  return false;
91  }
92 
93  return true;
94 }
95 
96 
97 // The error indicates the last socket operation has been
98 // interupted, the operation can be restarted immediately.
99 // The error will append on Windows only when the operation
100 // is interupted using `WSACancelBlockingCall`.
101 inline bool is_restartable_error(int error) { return (error == WSAEINTR); }
102 
103 
104 // The error indicates the last socket function on a non-blocking socket
105 // cannot be completed. This is a temporary condition and the caller can
106 // retry the operation later.
107 inline bool is_retryable_error(int error) { return (error == WSAEWOULDBLOCK); }
108 inline bool is_inprogress_error(int error) { return (error == WSAEWOULDBLOCK); }
109 
110 
111 // Returns a socket file descriptor for the specified options.
112 //
113 // NOTE: We default to no inheritance because we never inherit sockets.
114 // Overlapped I/O is enabled to match the default behavior of `::socket`.
116  int family,
117  int type,
118  int protocol,
119  DWORD flags = WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT)
120 {
121  SOCKET s = ::WSASocketW(family, type, protocol, nullptr, 0, flags);
122  if (s == INVALID_SOCKET) {
123  return WindowsSocketError();
124  }
125 
126  return s;
127 }
128 
129 // NOTE: The below wrappers are used to silence some implicit
130 // type-casting warnings.
131 
132 inline int_fd accept(
133  const int_fd& fd, sockaddr* addr, socklen_t* addrlen)
134 {
135  return int_fd(::accept(fd, addr, reinterpret_cast<int*>(addrlen)));
136 }
137 
138 
139 // NOTE: If `::bind` or `::connect` fail, they return `SOCKET_ERROR`, which is
140 // defined to be `-1`. Therefore, the error checking logic of `result < 0` used
141 // on POSIX will also work on Windows.
142 
143 inline int bind(
144  const int_fd& fd, const sockaddr* addr, socklen_t addrlen)
145 {
146  CHECK_LE(addrlen, INT32_MAX);
147  return ::bind(fd, addr, static_cast<int>(addrlen));
148 }
149 
150 
151 inline int connect(
152  const int_fd& fd, const sockaddr* address, socklen_t addrlen)
153 {
154  CHECK_LE(addrlen, INT32_MAX);
155  return ::connect(fd, address, static_cast<int>(addrlen));
156 }
157 
158 
159 inline ssize_t send(
160  const int_fd& fd, const void* buf, size_t len, int flags)
161 {
162  CHECK_LE(len, INT32_MAX);
164  fd, static_cast<const char*>(buf), static_cast<int>(len), flags);
165 }
166 
167 
168 inline ssize_t recv(const int_fd& fd, void* buf, size_t len, int flags)
169 {
170  CHECK_LE(len, INT32_MAX);
171  return ::recv(fd, static_cast<char*>(buf), static_cast<int>(len), flags);
172 }
173 
174 } // namespace net {
175 
176 #endif // __STOUT_OS_WINDOWS_SOCKET_HPP__
SSIZE_T ssize_t
Definition: windows.hpp:186
Try< int_fd > socket(int family, int type, int protocol)
Definition: socket.hpp:34
Definition: check.hpp:33
Try< Address > address(int_fd s)
Returns the Address with the assigned ip and assigned port.
Definition: network.hpp:79
Definition: error.hpp:123
bool is_inprogress_error(int error)
Definition: socket.hpp:71
int bind(const int_fd &fd, const sockaddr *addr, socklen_t addrlen)
Definition: socket.hpp:143
int_fd accept(const int_fd &fd, sockaddr *addr, socklen_t *addrlen)
Definition: socket.hpp:132
bool is_restartable_error(int error)
Definition: socket.hpp:56
ssize_t send(const int_fd &fd, const void *buf, size_t len, int flags)
Definition: socket.hpp:159
bool wsa_initialize()
Definition: socket.hpp:28
Definition: ip.hpp:70
ssize_t recv(const int_fd &fd, void *buf, size_t len, int flags)
Definition: socket.hpp:168
std::string error(const std::string &msg, uint32_t code)
bool wsa_cleanup()
Definition: socket.hpp:62
Try< uint32_t > type(const std::string &path)
int connect(const int_fd &fd, const sockaddr *address, socklen_t addrlen)
Definition: socket.hpp:151
int int_fd
Definition: int_fd.hpp:35
bool is_retryable_error(int error)
Definition: socket.hpp:65
Definition: parse.hpp:33