socketpair.cpp
Go to the documentation of this file.
00001 
00009 /*****************************************************************************
00010 ** Includes
00011 *****************************************************************************/
00012 
00013 #include <cerrno>
00014 #include "../../include/ecl/io/socketpair.hpp"
00015 
00016 /*****************************************************************************
00017 ** Namespaces
00018 *****************************************************************************/
00019 
00020 namespace ecl {
00021 
00022 SocketError socketpair(socket_descriptor socket_fd_pair[2], const bool non_blocking) {
00023 #ifdef ECL_IS_WIN32
00024 
00025     union {
00026        struct sockaddr_in inaddr;
00027        struct sockaddr addr;
00028     } a;
00029     socklen_t addrlen = sizeof(a.inaddr);
00030 
00031     /*********************
00032         ** Listener
00033         **********************/
00034     socket_descriptor listen_socket = INVALID_SOCKET;
00035     listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00036         if (listen_socket == INVALID_SOCKET) {
00037                 return SocketError(ConfigurationError);
00038         }
00039 
00040     // allow it to be bound to an address already in use - do we actually need this?
00041     int reuse = 1;
00042     if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, (socklen_t) sizeof(reuse)) == SOCKET_ERROR ) {
00043         ::closesocket(listen_socket);
00044                 return SocketError(ConfigurationError);
00045     }
00046 
00047     memset(&a, 0, sizeof(a));
00048     a.inaddr.sin_family = AF_INET;
00049     a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00050     // For TCP/IP, if the port is specified as zero, the service provider assigns
00051     // a unique port to the application from the dynamic client port range.
00052     a.inaddr.sin_port = 0;
00053 
00054     if  (bind(listen_socket, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) {
00055         ::closesocket(listen_socket);
00056                 return SocketError(ConfigurationError);
00057     }
00058     // we need this below because the system auto filled in some entries, e.g. port #
00059     if  (getsockname(listen_socket, &a.addr, &addrlen) == SOCKET_ERROR) {
00060         ::closesocket(listen_socket);
00061                 return SocketError(ConfigurationError);
00062     }
00063     // max 1 connection permitted
00064     if (listen(listen_socket, 1) == SOCKET_ERROR) {
00065         ::closesocket(listen_socket);
00066                 return SocketError(ConfigurationError);
00067     }
00068     /*********************
00069         ** Connection
00070         **********************/
00071     // initialise
00072     socket_fd_pair[0] = socket_fd_pair[1] = INVALID_SOCKET;
00073     // create first socket and connect to the listener
00074     // DWORD flags = (make_overlapped ? WSA_FLAG_OVERLAPPED : 0);
00075     DWORD overlapped_flag = 0;
00076     socket_fd_pair[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, overlapped_flag);
00077     if (socket_fd_pair[0] == INVALID_SOCKET) {
00078         ::closesocket(listen_socket);
00079         ::closesocket(socket_fd_pair[0]);
00080                 return SocketError(ConfigurationError);
00081     }
00082     // reusing the information from above to connect to the listener
00083     if (connect(socket_fd_pair[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) {
00084         ::closesocket(listen_socket);
00085         ::closesocket(socket_fd_pair[0]);
00086                 return SocketError(ConfigurationError);
00087     }
00088     /*********************
00089         ** Accept
00090         **********************/
00091     socket_fd_pair[1] = accept(listen_socket, NULL, NULL);
00092     if (socket_fd_pair[1] == INVALID_SOCKET) {
00093         ::closesocket(listen_socket);
00094         ::closesocket(socket_fd_pair[0]);
00095         ::closesocket(socket_fd_pair[1]);
00096                 return SocketError(ConfigurationError);
00097     }
00098         /*********************
00099         ** Nonblocking
00100         **********************/
00101     // should we do this or should we set io overlapping?
00102         unsigned long non_blocking_flag = 0; // by default is blocking.
00103         if ( non_blocking ) {
00104                 non_blocking_flag = 1;
00105                 if(ioctlsocket( socket_fd_pair[0], FIONBIO, &non_blocking_flag ) != 0 ) {
00106                         ::closesocket(listen_socket);
00107                         ::closesocket(socket_fd_pair[0]);
00108                         ::closesocket(socket_fd_pair[1]);
00109                         return SocketError(ConfigurationError);
00110                 }
00111                 if(ioctlsocket( socket_fd_pair[1], FIONBIO, &non_blocking_flag ) != 0 ) {
00112                         ::closesocket(listen_socket);
00113                         ::closesocket(socket_fd_pair[0]);
00114                         ::closesocket(socket_fd_pair[1]);
00115                         return SocketError(ConfigurationError);
00116                 }
00117         }
00118         /*********************
00119         ** Cleanup
00120         **********************/
00121     // the listener has done its job.
00122     ::closesocket(listen_socket);
00123 
00124 #else
00125         // returns 0 on success, -1 and errno otherwise
00126         int result = 0;
00127         if ( non_blocking ) {
00128 #if defined(SOCK_NONBLOCK)
00129                 result = ::socketpair(AF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0, socket_fd_pair);
00130 #else
00131                 result = ::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fd_pair);
00132                 // TODO: SOCK_NONBLOCK is n/a at least on macosx -> figure out how to make it non-blocking
00133 #endif
00134         } else {
00135                 ::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fd_pair);
00136         }
00137         if (result < 0) {
00138                 switch(errno) {
00139                         case (EAFNOSUPPORT) : { return SocketError(ArgNotSupportedError); } // AF_LOCAL is not supported
00140                         case (EFAULT) : { return SocketError(MemoryError); }
00141                         case (EMFILE) : { return SocketError(OutOfResourcesError); }
00142                         case (ENFILE) : { return SocketError(OutOfResourcesError); }
00143                         case (EOPNOTSUPP) : { return SocketError(ArgNotSupportedError); }
00144                         case (EPROTONOSUPPORT) : { return SocketError(ArgNotSupportedError); }
00145                         default : { return SocketError(UnknownError); }
00146                 }
00147         }
00148 #endif
00149         return SocketError(NoError);
00150 }
00151 
00152 } // namespace ecl
00153 
00154 
00155 
00156 
00157 /*****************************************************************************
00158 ** Graveyard
00159 *****************************************************************************/
00160 
00161 //      /*********************
00162 //      ** Notes
00163 //      **********************/
00164 //      // Using port 21 - is this a problem always using this port?
00165 //
00166 //      /******************************************
00167 //      ** Server
00168 //      *******************************************/
00169 //      struct addrinfo *result = NULL, *ptr = NULL, hints;
00170 //
00171 //      // windows sockets can't do AF_LOCAL
00172 //      ZeroMemory(&hints, sizeof (hints));
00173 //      hints.ai_family = AF_INET;
00174 //      hints.ai_socktype = SOCK_STREAM;
00175 //      hints.ai_protocol = IPPROTO_TCP;
00176 //      // AI_PASSIVE flag indicates the caller intends to use the
00177 //      // returned socket address structure in a call to the bind function.
00178 //      // When the AI_PASSIVE flag is set and nodename parameter to the
00179 //      // getaddrinfo function is a NULL pointer, the IP address portion
00180 //      // of the socket address structure is set to INADDR_ANY for IPv4
00181 //      // addresses or IN6ADDR_ANY_INIT for IPv6 addresses.
00182 //      hints.ai_flags = AI_PASSIVE;
00183 //
00184 //      // Resolve the local address and port to be used by the server
00185 //      // first argument is the nodename parameter as described above.
00186 //      int wsock_error = getaddrinfo(NULL, "21", &hints, &result);
00187 //      if (wsock_error != 0) {
00188 //              return SocketError(ConfigurationError);
00189 //      }
00190 //
00191 //      /*********************
00192 //      ** Server Socket
00193 //      **********************/
00194 //      socket_descriptor listen_socket = INVALID_SOCKET;
00195 //      // Create a SOCKET for the server to listen for client connections
00196 //      listen_socket = ::socket(result->ai_family, result->ai_socktype, result->ai_protocol);
00197 //      if (listen_socket == INVALID_SOCKET) {
00198 //          freeaddrinfo(result);
00199 //              return SocketError(ConfigurationError);
00200 //      }
00201 //
00202 //      /*********************
00203 //      ** Bind Server
00204 //      **********************/
00205 //      // Bind server to an address.
00206 //      wsock_error = bind( listen_socket, result->ai_addr, (int)result->ai_addrlen);
00207 //      if (wsock_error == SOCKET_ERROR) {
00208 //              freeaddrinfo(result);
00209 //              ::closesocket(listen_socket);
00210 //              return SocketError(ConfigurationError);
00211 //      }
00212 //      freeaddrinfo(result);
00213 //
00214 //      /*********************
00215 //      ** Listen for client
00216 //      **********************/
00217 //      if ( listen( listen_socket, SOMAXCONN ) == SOCKET_ERROR ) {
00218 //          closesocket(listen_socket);
00219 //              return SocketError(ConfigurationError);
00220 //      }
00221 //      socket_fd_pair[0] = INVALID_SOCKET;
00222 //
00223 //      /******************************************
00224 //      ** Client
00225 //      *******************************************/
00226 //      ZeroMemory( &hints, sizeof(hints) );
00227 //      hints.ai_family = AF_UNSPEC;
00228 //      hints.ai_socktype = SOCK_STREAM;
00229 //      hints.ai_protocol = IPPROTO_TCP;
00230 //      // Resolve the server address and port
00231 //      wsock_error = getaddrinfo("localhost", "21", &hints, &result);
00232 //      if (wsock_error != 0) {
00233 //          ::closesocket(listen_socket);
00234 //              return SocketError(ConfigurationError);
00235 //      }
00236 //      socket_fd_pair[1] = INVALID_SOCKET;
00237 //
00238 //      /*********************
00239 //      ** Create client
00240 //      **********************/
00241 //      ptr=result;
00242 //      socket_fd_pair[1] = ::socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
00243 //      if (socket_fd_pair[1] == INVALID_SOCKET) {
00244 //          ::closesocket(listen_socket);
00245 //          freeaddrinfo(result);
00246 //              return SocketError(ConfigurationError);
00247 //      }
00248 //
00249 //      /*********************
00250 //      ** Connect to server
00251 //      **********************/
00252 //      wsock_error = connect( socket_fd_pair[1], ptr->ai_addr, (int)ptr->ai_addrlen);
00253 //      if (wsock_error == SOCKET_ERROR) {
00254 //          ::closesocket(listen_socket);
00255 //          closesocket(socket_fd_pair[1]);
00256 //          socket_fd_pair[1] = INVALID_SOCKET;
00257 //              return SocketError(ConfigurationError);
00258 //      }
00259 //
00260 //      // Should really try the next address returned by getaddrinfo
00261 //      // if the connect call failed
00262 //      // But for this simple example we just free the resources
00263 //      // returned by getaddrinfo and print an error message
00264 //
00265 //      freeaddrinfo(result);
00266 //
00267 //      if (socket_fd_pair[1] == INVALID_SOCKET) {
00268 //              return SocketError(ConfigurationError);
00269 //      }
00270 //
00271 //      /*********************
00272 //      ** Accept connection
00273 //      **********************/
00274 //      // Server accepts a client socket
00275 //      socket_fd_pair[0] = accept(listen_socket, NULL, NULL);
00276 //      if (socket_fd_pair[0] == INVALID_SOCKET) {
00277 //          ::closesocket(listen_socket);
00278 //          ::closesocket(socket_fd_pair[1]);
00279 //              return SocketError(ConfigurationError);
00280 //      }
00281 //
00282 //
00283 //      /*********************
00284 //      ** Nonblocking
00285 //      **********************/
00286 //      unsigned long non_blocking_flag = 0; // by default is blocking.
00287 //      if ( non_blocking ) {
00288 //              non_blocking_flag = 1;
00289 //              if(ioctlsocket( socket_fd_pair[0], FIONBIO, &non_blocking_flag ) != 0 ) {
00290 //                  ::closesocket(listen_socket);
00291 //                  ::closesocket(socket_fd_pair[0]);
00292 //                  ::closesocket(socket_fd_pair[1]);
00293 //                      return SocketError(ConfigurationError);
00294 //              }
00295 //              if(ioctlsocket( socket_fd_pair[1], FIONBIO, &non_blocking_flag ) != 0 ) {
00296 //                  ::closesocket(listen_socket);
00297 //                  ::closesocket(socket_fd_pair[0]);
00298 //                  ::closesocket(socket_fd_pair[1]);
00299 //                      return SocketError(ConfigurationError);
00300 //              }
00301 //      }


ecl_io
Author(s): Daniel Stonier
autogenerated on Thu Jun 16 2016 09:47:15