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/windows.hpp> // For `WinSock2.h`.
20 
21 #include <stout/os/windows/fd.hpp>
22 
23 
24 namespace net {
25 
26 // Initialize Windows socket stack.
27 inline bool wsa_initialize()
28 {
29  // Initialize WinSock (request version 2.2).
30  WORD requestedVersion = MAKEWORD(2, 2);
31  WSADATA data;
32 
33  const int result = ::WSAStartup(requestedVersion, &data);
34  if (result != 0) {
35  const int error = ::WSAGetLastError();
36  LOG(ERROR) << "Could not initialize WinSock, error code : " << error;
37  return false;
38  }
39 
40  // Check that the WinSock version we got back is 2.2 or higher.
41  // The high-order byte specifies the minor version number.
42  if (LOBYTE(data.wVersion) < 2 ||
43  (LOBYTE(data.wVersion) == 2 && HIBYTE(data.wVersion) != 2)) {
44  LOG(ERROR) << "Incorrect WinSock version found : " << LOBYTE(data.wVersion)
45  << "." << HIBYTE(data.wVersion);
46 
47  // WinSock was initialized, we just didn't like the version, so we need to
48  // clean up.
49  if (::WSACleanup() != 0) {
50  const int error = ::WSAGetLastError();
51  LOG(ERROR) << "Could not cleanup WinSock, error code : " << error;
52  }
53 
54  return false;
55  }
56 
57  return true;
58 }
59 
60 
61 inline bool wsa_cleanup()
62 {
63  // Cleanup WinSock. Wait for any outstanding socket operations to complete
64  // before exiting. Retry for a maximum of 10 times at 1 second intervals.
65  int retriesLeft = 10;
66 
67  while (retriesLeft > 0) {
68  const int result = ::WSACleanup();
69  if (result != 0) {
70  const int error = ::WSAGetLastError();
71  // Make it idempotent.
72  if (error == WSANOTINITIALISED) {
73  return false;
74  }
75 
76  // Wait for any blocking calls to complete and retry after 1 second.
77  if (error == WSAEINPROGRESS) {
78  LOG(ERROR) << "Waiting for outstanding WinSock calls to complete.";
79  ::Sleep(1000);
80  retriesLeft--;
81  } else {
82  LOG(ERROR) << "Could not cleanup WinSock, error code : " << error;
83  return false;
84  }
85  }
86  break;
87  }
88  if (retriesLeft == 0) {
89  return false;
90  }
91 
92  return true;
93 }
94 
95 
96 // The error indicates the last socket operation has been
97 // interupted, the operation can be restarted immediately.
98 // The error will append on Windows only when the operation
99 // is interupted using `WSACancelBlockingCall`.
100 inline bool is_restartable_error(int error) { return (error == WSAEINTR); }
101 
102 
103 // The error indicates the last socket function on a non-blocking socket
104 // cannot be completed. This is a temporary condition and the caller can
105 // retry the operation later.
106 inline bool is_retryable_error(int error) { return (error == WSAEWOULDBLOCK); }
107 inline bool is_inprogress_error(int error) { return (error == WSAEWOULDBLOCK); }
108 
109 
110 // NOTE: The below wrappers are used to silence some implicit
111 // type-casting warnings.
112 
114  const os::WindowsFD& fd, sockaddr* addr, socklen_t* addrlen)
115 {
116  return ::accept(fd, addr, reinterpret_cast<int*>(addrlen));
117 }
118 
119 
120 inline int bind(
121  const os::WindowsFD& fd, const sockaddr* addr, socklen_t addrlen)
122 {
123  CHECK_LE(addrlen, INT32_MAX);
124  return ::bind(fd, addr, static_cast<int>(addrlen));
125 }
126 
127 
128 inline int connect(
129  const os::WindowsFD& fd, const sockaddr* address, socklen_t addrlen)
130 {
131  CHECK_LE(addrlen, INT32_MAX);
132  return ::connect(fd, address, static_cast<int>(addrlen));
133 }
134 
135 
136 inline ssize_t send(
137  const os::WindowsFD& fd, const void* buf, size_t len, int flags)
138 {
139  CHECK_LE(len, INT32_MAX);
141  fd, static_cast<const char*>(buf), static_cast<int>(len), flags);
142 }
143 
144 
145 inline ssize_t recv(const os::WindowsFD& fd, void* buf, size_t len, int flags)
146 {
147  CHECK_LE(len, INT32_MAX);
148  return ::recv(fd, static_cast<char*>(buf), static_cast<int>(len), flags);
149 }
150 
151 } // namespace net {
152 
153 #endif // __STOUT_OS_WINDOWS_SOCKET_HPP__
SSIZE_T ssize_t
Definition: windows.hpp:192
int bind(const os::WindowsFD &fd, const sockaddr *addr, socklen_t addrlen)
Definition: socket.hpp:120
os::WindowsFD accept(const os::WindowsFD &fd, sockaddr *addr, socklen_t *addrlen)
Definition: socket.hpp:113
Definition: fd.hpp:47
Try< Address > address(int_fd s)
Returns the Address with the assigned ip and assigned port.
Definition: network.hpp:79
int connect(const os::WindowsFD &fd, const sockaddr *address, socklen_t addrlen)
Definition: socket.hpp:128
bool is_inprogress_error(int error)
Definition: socket.hpp:48
ssize_t send(const os::WindowsFD &fd, const void *buf, size_t len, int flags)
Definition: socket.hpp:136
bool is_restartable_error(int error)
Definition: socket.hpp:33
bool wsa_initialize()
Definition: socket.hpp:27
ssize_t recv(const os::WindowsFD &fd, void *buf, size_t len, int flags)
Definition: socket.hpp:145
Future< Connection > connect(const network::Address &address, Scheme scheme)
Try< int_fd > accept(int_fd s)
Definition: network.hpp:31
#define flags
Definition: decoder.hpp:18
std::string error(const std::string &msg, uint32_t code)
bool wsa_cleanup()
Definition: socket.hpp:61
Try< Nothing > bind(int_fd s, const Address &address)
Definition: network.hpp:46
bool is_retryable_error(int error)
Definition: socket.hpp:42