lib/socketpair.cpp
Go to the documentation of this file.
1 
9 /*****************************************************************************
10 ** Includes
11 *****************************************************************************/
12 
13 #include <cerrno>
14 #include "../../include/ecl/io/socketpair.hpp"
15 
16 /*****************************************************************************
17 ** Namespaces
18 *****************************************************************************/
19 
20 namespace ecl {
21 
22 SocketError socketpair(socket_descriptor socket_fd_pair[2], const bool non_blocking) {
23 #ifdef ECL_IS_WIN32
24 
25  union {
26  struct sockaddr_in inaddr;
27  struct sockaddr addr;
28  } a;
29  socklen_t addrlen = sizeof(a.inaddr);
30 
31  /*********************
32  ** Listener
33  **********************/
34  socket_descriptor listen_socket = INVALID_SOCKET;
35  listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
36  if (listen_socket == INVALID_SOCKET) {
38  }
39 
40  // allow it to be bound to an address already in use - do we actually need this?
41  int reuse = 1;
42  if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, (socklen_t) sizeof(reuse)) == SOCKET_ERROR ) {
43  ::closesocket(listen_socket);
45  }
46 
47  memset(&a, 0, sizeof(a));
48  a.inaddr.sin_family = AF_INET;
49  a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
50  // For TCP/IP, if the port is specified as zero, the service provider assigns
51  // a unique port to the application from the dynamic client port range.
52  a.inaddr.sin_port = 0;
53 
54  if (bind(listen_socket, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) {
55  ::closesocket(listen_socket);
57  }
58  // we need this below because the system auto filled in some entries, e.g. port #
59  if (getsockname(listen_socket, &a.addr, &addrlen) == SOCKET_ERROR) {
60  ::closesocket(listen_socket);
62  }
63  // max 1 connection permitted
64  if (listen(listen_socket, 1) == SOCKET_ERROR) {
65  ::closesocket(listen_socket);
67  }
68  /*********************
69  ** Connection
70  **********************/
71  // initialise
72  socket_fd_pair[0] = socket_fd_pair[1] = INVALID_SOCKET;
73  // create first socket and connect to the listener
74  // DWORD flags = (make_overlapped ? WSA_FLAG_OVERLAPPED : 0);
75  DWORD overlapped_flag = 0;
76  socket_fd_pair[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, overlapped_flag);
77  if (socket_fd_pair[0] == INVALID_SOCKET) {
78  ::closesocket(listen_socket);
79  ::closesocket(socket_fd_pair[0]);
81  }
82  // reusing the information from above to connect to the listener
83  if (connect(socket_fd_pair[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) {
84  ::closesocket(listen_socket);
85  ::closesocket(socket_fd_pair[0]);
87  }
88  /*********************
89  ** Accept
90  **********************/
91  socket_fd_pair[1] = accept(listen_socket, NULL, NULL);
92  if (socket_fd_pair[1] == INVALID_SOCKET) {
93  ::closesocket(listen_socket);
94  ::closesocket(socket_fd_pair[0]);
95  ::closesocket(socket_fd_pair[1]);
97  }
98  /*********************
99  ** Nonblocking
100  **********************/
101  // should we do this or should we set io overlapping?
102  unsigned long non_blocking_flag = 0; // by default is blocking.
103  if ( non_blocking ) {
104  non_blocking_flag = 1;
105  if(ioctlsocket( socket_fd_pair[0], FIONBIO, &non_blocking_flag ) != 0 ) {
106  ::closesocket(listen_socket);
107  ::closesocket(socket_fd_pair[0]);
108  ::closesocket(socket_fd_pair[1]);
110  }
111  if(ioctlsocket( socket_fd_pair[1], FIONBIO, &non_blocking_flag ) != 0 ) {
112  ::closesocket(listen_socket);
113  ::closesocket(socket_fd_pair[0]);
114  ::closesocket(socket_fd_pair[1]);
116  }
117  }
118  /*********************
119  ** Cleanup
120  **********************/
121  // the listener has done its job.
122  ::closesocket(listen_socket);
123 
124 #else
125  // returns 0 on success, -1 and errno otherwise
126  int result = 0;
127  if ( non_blocking ) {
128 #if defined(SOCK_NONBLOCK)
129  result = ::socketpair(AF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0, socket_fd_pair);
130 #else
131  result = ::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fd_pair);
132  // TODO: SOCK_NONBLOCK is n/a at least on macosx -> figure out how to make it non-blocking
133 #endif
134  } else {
135  ::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fd_pair);
136  }
137  if (result < 0) {
138  switch(errno) {
139  case (EAFNOSUPPORT) : { return SocketError(ArgNotSupportedError); } // AF_LOCAL is not supported
140  case (EFAULT) : { return SocketError(MemoryError); }
141  case (EMFILE) : { return SocketError(OutOfResourcesError); }
142  case (ENFILE) : { return SocketError(OutOfResourcesError); }
143  case (EOPNOTSUPP) : { return SocketError(ArgNotSupportedError); }
144  case (EPROTONOSUPPORT) : { return SocketError(ArgNotSupportedError); }
145  default : { return SocketError(UnknownError); }
146  }
147  }
148 #endif
149  return SocketError(NoError);
150 }
151 
152 } // namespace ecl
153 
154 
155 
156 
157 /*****************************************************************************
158 ** Graveyard
159 *****************************************************************************/
160 
161 // /*********************
162 // ** Notes
163 // **********************/
164 // // Using port 21 - is this a problem always using this port?
165 //
166 // /******************************************
167 // ** Server
168 // *******************************************/
169 // struct addrinfo *result = NULL, *ptr = NULL, hints;
170 //
171 // // windows sockets can't do AF_LOCAL
172 // ZeroMemory(&hints, sizeof (hints));
173 // hints.ai_family = AF_INET;
174 // hints.ai_socktype = SOCK_STREAM;
175 // hints.ai_protocol = IPPROTO_TCP;
176 // // AI_PASSIVE flag indicates the caller intends to use the
177 // // returned socket address structure in a call to the bind function.
178 // // When the AI_PASSIVE flag is set and nodename parameter to the
179 // // getaddrinfo function is a NULL pointer, the IP address portion
180 // // of the socket address structure is set to INADDR_ANY for IPv4
181 // // addresses or IN6ADDR_ANY_INIT for IPv6 addresses.
182 // hints.ai_flags = AI_PASSIVE;
183 //
184 // // Resolve the local address and port to be used by the server
185 // // first argument is the nodename parameter as described above.
186 // int wsock_error = getaddrinfo(NULL, "21", &hints, &result);
187 // if (wsock_error != 0) {
188 // return SocketError(ConfigurationError);
189 // }
190 //
191 // /*********************
192 // ** Server Socket
193 // **********************/
194 // socket_descriptor listen_socket = INVALID_SOCKET;
195 // // Create a SOCKET for the server to listen for client connections
196 // listen_socket = ::socket(result->ai_family, result->ai_socktype, result->ai_protocol);
197 // if (listen_socket == INVALID_SOCKET) {
198 // freeaddrinfo(result);
199 // return SocketError(ConfigurationError);
200 // }
201 //
202 // /*********************
203 // ** Bind Server
204 // **********************/
205 // // Bind server to an address.
206 // wsock_error = bind( listen_socket, result->ai_addr, (int)result->ai_addrlen);
207 // if (wsock_error == SOCKET_ERROR) {
208 // freeaddrinfo(result);
209 // ::closesocket(listen_socket);
210 // return SocketError(ConfigurationError);
211 // }
212 // freeaddrinfo(result);
213 //
214 // /*********************
215 // ** Listen for client
216 // **********************/
217 // if ( listen( listen_socket, SOMAXCONN ) == SOCKET_ERROR ) {
218 // closesocket(listen_socket);
219 // return SocketError(ConfigurationError);
220 // }
221 // socket_fd_pair[0] = INVALID_SOCKET;
222 //
223 // /******************************************
224 // ** Client
225 // *******************************************/
226 // ZeroMemory( &hints, sizeof(hints) );
227 // hints.ai_family = AF_UNSPEC;
228 // hints.ai_socktype = SOCK_STREAM;
229 // hints.ai_protocol = IPPROTO_TCP;
230 // // Resolve the server address and port
231 // wsock_error = getaddrinfo("localhost", "21", &hints, &result);
232 // if (wsock_error != 0) {
233 // ::closesocket(listen_socket);
234 // return SocketError(ConfigurationError);
235 // }
236 // socket_fd_pair[1] = INVALID_SOCKET;
237 //
238 // /*********************
239 // ** Create client
240 // **********************/
241 // ptr=result;
242 // socket_fd_pair[1] = ::socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
243 // if (socket_fd_pair[1] == INVALID_SOCKET) {
244 // ::closesocket(listen_socket);
245 // freeaddrinfo(result);
246 // return SocketError(ConfigurationError);
247 // }
248 //
249 // /*********************
250 // ** Connect to server
251 // **********************/
252 // wsock_error = connect( socket_fd_pair[1], ptr->ai_addr, (int)ptr->ai_addrlen);
253 // if (wsock_error == SOCKET_ERROR) {
254 // ::closesocket(listen_socket);
255 // closesocket(socket_fd_pair[1]);
256 // socket_fd_pair[1] = INVALID_SOCKET;
257 // return SocketError(ConfigurationError);
258 // }
259 //
260 // // Should really try the next address returned by getaddrinfo
261 // // if the connect call failed
262 // // But for this simple example we just free the resources
263 // // returned by getaddrinfo and print an error message
264 //
265 // freeaddrinfo(result);
266 //
267 // if (socket_fd_pair[1] == INVALID_SOCKET) {
268 // return SocketError(ConfigurationError);
269 // }
270 //
271 // /*********************
272 // ** Accept connection
273 // **********************/
274 // // Server accepts a client socket
275 // socket_fd_pair[0] = accept(listen_socket, NULL, NULL);
276 // if (socket_fd_pair[0] == INVALID_SOCKET) {
277 // ::closesocket(listen_socket);
278 // ::closesocket(socket_fd_pair[1]);
279 // return SocketError(ConfigurationError);
280 // }
281 //
282 //
283 // /*********************
284 // ** Nonblocking
285 // **********************/
286 // unsigned long non_blocking_flag = 0; // by default is blocking.
287 // if ( non_blocking ) {
288 // non_blocking_flag = 1;
289 // if(ioctlsocket( socket_fd_pair[0], FIONBIO, &non_blocking_flag ) != 0 ) {
290 // ::closesocket(listen_socket);
291 // ::closesocket(socket_fd_pair[0]);
292 // ::closesocket(socket_fd_pair[1]);
293 // return SocketError(ConfigurationError);
294 // }
295 // if(ioctlsocket( socket_fd_pair[1], FIONBIO, &non_blocking_flag ) != 0 ) {
296 // ::closesocket(listen_socket);
297 // ::closesocket(socket_fd_pair[0]);
298 // ::closesocket(socket_fd_pair[1]);
299 // return SocketError(ConfigurationError);
300 // }
301 // }
ecl_io_PUBLIC SocketError socketpair(socket_descriptor socket_fd_pair[2], const bool non_blocking=false)
Creates a socket pair internal to the current process.
UnknownError
ConfigurationError
int socket_descriptor
Cross-platform typedef for a socket file descriptor.
Definition: sockets.hpp:58
OutOfResourcesError
MemoryError
ArgNotSupportedError
Extends the generic error handler with socket specific error strings.
Definition: sockets.hpp:68


ecl_io
Author(s): Daniel Stonier
autogenerated on Fri Jun 7 2019 21:52:45