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                 result = ::socketpair(AF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0, socket_fd_pair);
00129         } else {
00130                 ::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fd_pair);
00131         }
00132         if (result < 0) {
00133                 switch(errno) {
00134                         case (EAFNOSUPPORT) : { return SocketError(ArgNotSupportedError); } // AF_LOCAL is not supported
00135                         case (EFAULT) : { return SocketError(MemoryError); }
00136                         case (EMFILE) : { return SocketError(OutOfResourcesError); }
00137                         case (ENFILE) : { return SocketError(OutOfResourcesError); }
00138                         case (EOPNOTSUPP) : { return SocketError(ArgNotSupportedError); }
00139                         case (EPROTONOSUPPORT) : { return SocketError(ArgNotSupportedError); }
00140                         default : { return SocketError(UnknownError); }
00141                 }
00142         }
00143 #endif
00144         return SocketError(NoError);
00145 }
00146 
00147 } // namespace ecl
00148 
00149 
00150 
00151 
00152 /*****************************************************************************
00153 ** Graveyard
00154 *****************************************************************************/
00155 
00156 //      /*********************
00157 //      ** Notes
00158 //      **********************/
00159 //      // Using port 21 - is this a problem always using this port?
00160 //
00161 //      /******************************************
00162 //      ** Server
00163 //      *******************************************/
00164 //      struct addrinfo *result = NULL, *ptr = NULL, hints;
00165 //
00166 //      // windows sockets can't do AF_LOCAL
00167 //      ZeroMemory(&hints, sizeof (hints));
00168 //      hints.ai_family = AF_INET;
00169 //      hints.ai_socktype = SOCK_STREAM;
00170 //      hints.ai_protocol = IPPROTO_TCP;
00171 //      // AI_PASSIVE flag indicates the caller intends to use the
00172 //      // returned socket address structure in a call to the bind function.
00173 //      // When the AI_PASSIVE flag is set and nodename parameter to the
00174 //      // getaddrinfo function is a NULL pointer, the IP address portion
00175 //      // of the socket address structure is set to INADDR_ANY for IPv4
00176 //      // addresses or IN6ADDR_ANY_INIT for IPv6 addresses.
00177 //      hints.ai_flags = AI_PASSIVE;
00178 //
00179 //      // Resolve the local address and port to be used by the server
00180 //      // first argument is the nodename parameter as described above.
00181 //      int wsock_error = getaddrinfo(NULL, "21", &hints, &result);
00182 //      if (wsock_error != 0) {
00183 //              return SocketError(ConfigurationError);
00184 //      }
00185 //
00186 //      /*********************
00187 //      ** Server Socket
00188 //      **********************/
00189 //      socket_descriptor listen_socket = INVALID_SOCKET;
00190 //      // Create a SOCKET for the server to listen for client connections
00191 //      listen_socket = ::socket(result->ai_family, result->ai_socktype, result->ai_protocol);
00192 //      if (listen_socket == INVALID_SOCKET) {
00193 //          freeaddrinfo(result);
00194 //              return SocketError(ConfigurationError);
00195 //      }
00196 //
00197 //      /*********************
00198 //      ** Bind Server
00199 //      **********************/
00200 //      // Bind server to an address.
00201 //      wsock_error = bind( listen_socket, result->ai_addr, (int)result->ai_addrlen);
00202 //      if (wsock_error == SOCKET_ERROR) {
00203 //              freeaddrinfo(result);
00204 //              ::closesocket(listen_socket);
00205 //              return SocketError(ConfigurationError);
00206 //      }
00207 //      freeaddrinfo(result);
00208 //
00209 //      /*********************
00210 //      ** Listen for client
00211 //      **********************/
00212 //      if ( listen( listen_socket, SOMAXCONN ) == SOCKET_ERROR ) {
00213 //          closesocket(listen_socket);
00214 //              return SocketError(ConfigurationError);
00215 //      }
00216 //      socket_fd_pair[0] = INVALID_SOCKET;
00217 //
00218 //      /******************************************
00219 //      ** Client
00220 //      *******************************************/
00221 //      ZeroMemory( &hints, sizeof(hints) );
00222 //      hints.ai_family = AF_UNSPEC;
00223 //      hints.ai_socktype = SOCK_STREAM;
00224 //      hints.ai_protocol = IPPROTO_TCP;
00225 //      // Resolve the server address and port
00226 //      wsock_error = getaddrinfo("localhost", "21", &hints, &result);
00227 //      if (wsock_error != 0) {
00228 //          ::closesocket(listen_socket);
00229 //              return SocketError(ConfigurationError);
00230 //      }
00231 //      socket_fd_pair[1] = INVALID_SOCKET;
00232 //
00233 //      /*********************
00234 //      ** Create client
00235 //      **********************/
00236 //      ptr=result;
00237 //      socket_fd_pair[1] = ::socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
00238 //      if (socket_fd_pair[1] == INVALID_SOCKET) {
00239 //          ::closesocket(listen_socket);
00240 //          freeaddrinfo(result);
00241 //              return SocketError(ConfigurationError);
00242 //      }
00243 //
00244 //      /*********************
00245 //      ** Connect to server
00246 //      **********************/
00247 //      wsock_error = connect( socket_fd_pair[1], ptr->ai_addr, (int)ptr->ai_addrlen);
00248 //      if (wsock_error == SOCKET_ERROR) {
00249 //          ::closesocket(listen_socket);
00250 //          closesocket(socket_fd_pair[1]);
00251 //          socket_fd_pair[1] = INVALID_SOCKET;
00252 //              return SocketError(ConfigurationError);
00253 //      }
00254 //
00255 //      // Should really try the next address returned by getaddrinfo
00256 //      // if the connect call failed
00257 //      // But for this simple example we just free the resources
00258 //      // returned by getaddrinfo and print an error message
00259 //
00260 //      freeaddrinfo(result);
00261 //
00262 //      if (socket_fd_pair[1] == INVALID_SOCKET) {
00263 //              return SocketError(ConfigurationError);
00264 //      }
00265 //
00266 //      /*********************
00267 //      ** Accept connection
00268 //      **********************/
00269 //      // Server accepts a client socket
00270 //      socket_fd_pair[0] = accept(listen_socket, NULL, NULL);
00271 //      if (socket_fd_pair[0] == INVALID_SOCKET) {
00272 //          ::closesocket(listen_socket);
00273 //          ::closesocket(socket_fd_pair[1]);
00274 //              return SocketError(ConfigurationError);
00275 //      }
00276 //
00277 //
00278 //      /*********************
00279 //      ** Nonblocking
00280 //      **********************/
00281 //      unsigned long non_blocking_flag = 0; // by default is blocking.
00282 //      if ( non_blocking ) {
00283 //              non_blocking_flag = 1;
00284 //              if(ioctlsocket( socket_fd_pair[0], FIONBIO, &non_blocking_flag ) != 0 ) {
00285 //                  ::closesocket(listen_socket);
00286 //                  ::closesocket(socket_fd_pair[0]);
00287 //                  ::closesocket(socket_fd_pair[1]);
00288 //                      return SocketError(ConfigurationError);
00289 //              }
00290 //              if(ioctlsocket( socket_fd_pair[1], FIONBIO, &non_blocking_flag ) != 0 ) {
00291 //                  ::closesocket(listen_socket);
00292 //                  ::closesocket(socket_fd_pair[0]);
00293 //                  ::closesocket(socket_fd_pair[1]);
00294 //                      return SocketError(ConfigurationError);
00295 //              }
00296 //      }


ecl_io
Author(s): Daniel Stonier
autogenerated on Sun Oct 5 2014 23:35:30