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 // }