X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2f7c2af5474ea532899a7311efb31a55a555f372..c6e62f74fcac5b62889b59e7ce7a41d0ce884d7b:/src/msw/gsocket.c diff --git a/src/msw/gsocket.c b/src/msw/gsocket.c index da6e95cfea..10c1b2ab4f 100644 --- a/src/msw/gsocket.c +++ b/src/msw/gsocket.c @@ -7,12 +7,18 @@ */ #ifndef __GSOCKET_STANDALONE__ - #include "wx/setup.h" +#endif + +#if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) + + +#ifndef __GSOCKET_STANDALONE__ + #include "wx/msw/gsockmsw.h" #include "wx/gsocket.h" -#define INSTANCE wxhInstance +#define INSTANCE wxGetInstance() #else @@ -23,13 +29,11 @@ * be available and it must containt the app's instance * handle. */ -#define INSTANCE hInst +#define INSTANCE hInst #endif /* __GSOCKET_STANDALONE__ */ -#if defined(__GSOCKET_STANDALONE__) || defined(wxUSE_SOCKETS) - #include #include #include @@ -137,7 +141,8 @@ GSocket *GSocket_new() socket->m_stream = TRUE; socket->m_non_blocking = FALSE; socket->m_timeout.tv_sec = 10 * 60; /* 10 minutes */ - socket->m_timeout.tv_usec = 0; + socket->m_timeout.tv_usec = 0; + socket->m_detected = 0; /* Allocate a new message number for this socket */ EnterCriticalSection(&critical); @@ -167,26 +172,23 @@ void GSocket_destroy(GSocket *socket) { assert(socket != NULL); - /* We don't want more event notifications; so first of all we - * remove the socket from the list (NOTE: we won't get a CLOSE - * event for this socket if it wasn't closed before). - */ + /* Remove the socket from the list */ EnterCriticalSection(&critical); socketList[(socket->m_msgnumber - WM_USER)] = NULL; LeaveCriticalSection(&critical); - /* We check that the socket is really shutdowned */ + /* Check that the socket is really shutdowned */ if (socket->m_fd != INVALID_SOCKET) GSocket_Shutdown(socket); - /* We destroy private addresses */ + /* Destroy private addresses */ if (socket->m_local) GAddress_destroy(socket->m_local); if (socket->m_peer) GAddress_destroy(socket->m_peer); - /* We destroy socket itself */ + /* Destroy socket itself */ free(socket); } @@ -196,7 +198,7 @@ void GSocket_Shutdown(GSocket *socket) assert(socket != NULL); - /* If socket has been created, we shutdown it */ + /* If socket has been created, shutdown it */ if (socket->m_fd != INVALID_SOCKET) { shutdown(socket->m_fd, 2); @@ -204,13 +206,12 @@ void GSocket_Shutdown(GSocket *socket) socket->m_fd = INVALID_SOCKET; } - /* We disable GUI callbacks */ + /* Disable GUI callbacks */ for (evt = 0; evt < GSOCK_MAX_EVENT; evt++) - { socket->m_cbacks[evt] = NULL; - } - _GSocket_Configure_Callbacks(socket); + socket->m_detected = 0; + _GSocket_Disable_Events(socket); } /* Address handling */ @@ -261,7 +262,8 @@ GAddress *GSocket_GetLocal(GSocket *socket) { GAddress *address; struct sockaddr addr; - SOCKLEN_T size; + SOCKLEN_T size = sizeof(addr); + GSocketError err; assert(socket != NULL); @@ -288,10 +290,11 @@ GAddress *GSocket_GetLocal(GSocket *socket) socket->m_error = GSOCK_MEMERR; return NULL; } - if (_GAddress_translate_from(address, &addr, size) != GSOCK_NOERROR) + err = _GAddress_translate_from(address, &addr, size); + if (err != GSOCK_NOERROR) { - socket->m_error = GSOCK_MEMERR; GAddress_destroy(address); + socket->m_error = err; return NULL; } @@ -350,7 +353,7 @@ GSocketError GSocket_SetServer(GSocket *sck) } ioctlsocket(sck->m_fd, FIONBIO, (u_long FAR *) &arg); - _GSocket_Configure_Callbacks(sck); + _GSocket_Enable_Events(sck); /* Bind the socket to the LOCAL address */ if (bind(sck->m_fd, sck->m_local->m_addr, sck->m_local->m_len) != 0) @@ -371,7 +374,7 @@ GSocketError GSocket_SetServer(GSocket *sck) } return GSOCK_NOERROR; -} +} /* GSocket_WaitConnection: * Waits for an incoming client connection. @@ -379,11 +382,15 @@ GSocketError GSocket_SetServer(GSocket *sck) GSocket *GSocket_WaitConnection(GSocket *sck) { GSocket *connection; + struct sockaddr from; + SOCKLEN_T fromlen = sizeof(from); + GSocketError err; u_long arg = 1; assert(sck != NULL); - /* If the socket has already been created, we exit immediately */ + sck->m_detected &= ~GSOCK_CONNECTION_FLAG; + if (sck->m_fd == INVALID_SOCKET || !sck->m_server) { sck->m_error = GSOCK_INVSOCK; @@ -407,7 +414,7 @@ GSocket *GSocket_WaitConnection(GSocket *sck) return NULL; } - connection->m_fd = accept(sck->m_fd, NULL, NULL); + connection->m_fd = accept(sck->m_fd, &from, &fromlen); if (connection->m_fd == INVALID_SOCKET) { @@ -425,8 +432,25 @@ GSocket *GSocket_WaitConnection(GSocket *sck) connection->m_stream = TRUE; connection->m_oriented = TRUE; + /* Setup the peer address field */ + connection->m_peer = GAddress_new(); + if (!connection->m_peer) + { + GSocket_destroy(connection); + sck->m_error = GSOCK_MEMERR; + return NULL; + } + err = _GAddress_translate_from(connection->m_peer, &from, fromlen); + if (err != GSOCK_NOERROR) + { + GAddress_destroy(connection->m_peer); + GSocket_destroy(connection); + sck->m_error = err; + return NULL; + } + ioctlsocket(connection->m_fd, FIONBIO, (u_long FAR *) &arg); - _GSocket_Configure_Callbacks(connection); + _GSocket_Enable_Events(connection); return connection; } @@ -466,7 +490,7 @@ GSocketError GSocket_SetNonOriented(GSocket *sck) } ioctlsocket(sck->m_fd, FIONBIO, (u_long FAR *) &arg); - _GSocket_Configure_Callbacks(sck); + _GSocket_Enable_Events(sck); /* Bind it to the LOCAL address */ if (bind(sck->m_fd, sck->m_local->m_addr, sck->m_local->m_len) != 0) @@ -482,15 +506,15 @@ GSocketError GSocket_SetNonOriented(GSocket *sck) GSocketError GSocket_SetBroadcast(GSocket *sck) { - BOOL b; + BOOL b = TRUE; assert(sck != NULL); if (GSocket_SetNonOriented(sck) != GSOCK_NOERROR) return sck->m_error; - b = TRUE; - setsockopt(sck->m_fd, SOL_SOCKET, SO_BROADCAST, (const char FAR *) &b, sizeof(b)); + setsockopt(sck->m_fd, SOL_SOCKET, SO_BROADCAST, + (const char FAR *) &b, sizeof(b)); return GSOCK_NOERROR; } @@ -513,6 +537,8 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream) assert(sck != NULL); + sck->m_detected &= ~GSOCK_CONNECTION_FLAG; + if (sck->m_fd != INVALID_SOCKET) { sck->m_error = GSOCK_INVSOCK; @@ -545,7 +571,7 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream) } ioctlsocket(sck->m_fd, FIONBIO, (u_long FAR *) &arg); - _GSocket_Configure_Callbacks(sck); + _GSocket_Enable_Events(sck); /* Connect it to the PEER address, with a timeout (see below) */ ret = connect(sck->m_fd, sck->m_peer->m_addr, sck->m_peer->m_len); @@ -601,25 +627,64 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream) /* Like recv(), send(), ... */ int GSocket_Read(GSocket *socket, char *buffer, int size) { + int ret; + assert(socket != NULL); + socket->m_detected &= ~GSOCK_INPUT_FLAG; + if (socket->m_fd == INVALID_SOCKET || socket->m_server) { socket->m_error = GSOCK_INVSOCK; return -1; } + /* If the socket is blocking, wait for data (with a timeout) */ if (_GSocket_Input_Timeout(socket) == GSOCK_TIMEDOUT) return -1; + /* Read the data */ if (socket->m_stream) - return _GSocket_Recv_Stream(socket, buffer, size); + ret = _GSocket_Recv_Stream(socket, buffer, size); else - return _GSocket_Recv_Dgram(socket, buffer, size); + ret = _GSocket_Recv_Dgram(socket, buffer, size); + + if (ret == SOCKET_ERROR) + { + /* NOTE: Window sockets exhibit a very strange property; + * if the socket is in non-blocking mode (which is always + * the case here, no matter the setting of GSocket itself) + * a call to send() can fail with EWOULDBLOCK even when + * select() says that the socket is writable. + * + * This can break several things because, usually, if + * select() says that the socket is writable, it is + * assumed that send() won't fail. To avoid this, we + * return 0 instead of -1 for this special case. + * + * XXX - this comment seems not to belong here, and also + * the code is not consistent with the unix version of + * gsocket... what to do? (GRG) + */ + if (WSAGetLastError() != WSAEWOULDBLOCK) + { + socket->m_error = GSOCK_IOERR; + return -1; + } + else + { + socket->m_error = GSOCK_WOULDBLOCK; + return 0; + } + } + + return ret; } int GSocket_Write(GSocket *socket, const char *buffer, int size) { + int ret; + assert(socket != NULL); if (socket->m_fd == INVALID_SOCKET || socket->m_server) @@ -628,13 +693,28 @@ int GSocket_Write(GSocket *socket, const char *buffer, int size) return -1; } + /* If the socket is blocking, wait for writability (with a timeout) */ if (_GSocket_Output_Timeout(socket) == GSOCK_TIMEDOUT) return -1; + /* Read the data */ if (socket->m_stream) - return _GSocket_Send_Stream(socket, buffer, size); + ret = _GSocket_Send_Stream(socket, buffer, size); else - return _GSocket_Send_Dgram(socket, buffer, size); + ret = _GSocket_Send_Dgram(socket, buffer, size); + + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != WSAEWOULDBLOCK) + socket->m_error = GSOCK_IOERR; + else + socket->m_error = GSOCK_WOULDBLOCK; + + socket->m_detected &= ~GSOCK_OUTPUT_FLAG; + return -1; + } + + return ret; } /* GSocket_Select: @@ -646,53 +726,9 @@ int GSocket_Write(GSocket *socket, const char *buffer, int size) */ GSocketEventFlags GSocket_Select(GSocket *socket, GSocketEventFlags flags) { - fd_set readfds, writefds, exceptfds; - struct timeval tv; - GSocketEventFlags mask; - assert(socket != NULL); - if (socket->m_fd == INVALID_SOCKET) - { - socket->m_error = GSOCK_INVSOCK; - return FALSE; - } - - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&exceptfds); - FD_SET(socket->m_fd, &readfds); - FD_SET(socket->m_fd, &writefds); - FD_SET(socket->m_fd, &exceptfds); - - tv.tv_sec = 0; - tv.tv_usec = 0; - select(socket->m_fd + 1, &readfds, &writefds, &exceptfds, &tv); - - mask = 0; - - /* If select() says that the socket is readable, then we have - * no way to distinguish if that means 'data available' (to - * recv) or 'incoming connection' (to accept). The same goes - * for writability: we cannot distinguish between 'you can - * send data' and 'connection request completed'. So we will - * assume the following: if the flag was set upon entry, - * that means that the event was possible. - */ - if (FD_ISSET(socket->m_fd, &readfds)) - { - mask |= (flags & GSOCK_CONNECTION_FLAG); - mask |= (flags & GSOCK_INPUT_FLAG); - } - if (FD_ISSET(socket->m_fd, &writefds)) - { - mask |= (flags & GSOCK_CONNECTION_FLAG); - mask |= (flags & GSOCK_OUTPUT_FLAG); - } - if (FD_ISSET(socket->m_fd, &exceptfds)) - mask |= (flags & GSOCK_LOST_FLAG); - - return mask; + return (flags & socket->m_detected); } /* Flags */ @@ -712,12 +748,12 @@ void GSocket_SetNonBlocking(GSocket *socket, bool non_block) * Sets the timeout for blocking calls. Time is * expressed in milliseconds. */ -void GSocket_SetTimeout(GSocket *socket, unsigned long millisecs) +void GSocket_SetTimeout(GSocket *socket, unsigned long millis) { assert(socket != NULL); - socket->m_timeout.tv_sec = (millisecs / 1000); - socket->m_timeout.tv_usec = (millisecs % 1000) * 1000; + socket->m_timeout.tv_sec = (millis / 1000); + socket->m_timeout.tv_usec = (millis % 1000) * 1000; } /* GSocket_GetError: @@ -765,15 +801,12 @@ void GSocket_SetCallback(GSocket *socket, GSocketEventFlags flags, for (count = 0; count < GSOCK_MAX_EVENT; count++) { - /* We test each flag and enable the corresponding events */ if ((flags & (1 << count)) != 0) { socket->m_cbacks[count] = callback; socket->m_data[count] = cdata; } } - - _GSocket_Configure_Callbacks(socket); } /* GSocket_UnsetCallback: @@ -788,44 +821,47 @@ void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags flags) for (count = 0; count < GSOCK_MAX_EVENT; count++) { - /* We test each flag and disable the corresponding events */ if ((flags & (1 << count)) != 0) { socket->m_cbacks[count] = NULL; + socket->m_data[count] = NULL; } } - - _GSocket_Configure_Callbacks(socket); } /* Internals */ -void _GSocket_Configure_Callbacks(GSocket *socket) +/* _GSocket_Enable_Events: + * We enable all event notifications here (we need to be notified + * of all events for internal processing) but we will only notify + * users when an appropiate callback function has been installed. + */ +void _GSocket_Enable_Events(GSocket *socket) { - long mask = 0; - int count; - - if (socket->m_fd == INVALID_SOCKET) - return; + assert (socket != NULL); - for (count = 0; count < GSOCK_MAX_EVENT; count++) + if (socket->m_fd != INVALID_SOCKET) { - if (socket->m_cbacks[count] != NULL) - { - switch (count) - { - case GSOCK_INPUT: mask |= FD_READ; break; - case GSOCK_OUTPUT: mask |= FD_WRITE; break; - case GSOCK_CONNECTION: mask |= (FD_ACCEPT | FD_CONNECT); break; - case GSOCK_LOST: mask |= FD_CLOSE; break; - } - } + WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, + FD_READ | FD_WRITE | FD_ACCEPT | FD_CONNECT | FD_CLOSE); } +} - WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, mask); +/* _GSocket_Disable_Events: + * Disable event notifications (when shutdowning the socket) + */ +void _GSocket_Disable_Events(GSocket *socket) +{ + assert (socket != NULL); + + if (socket->m_fd != INVALID_SOCKET) + { + WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, 0); + } } + LRESULT CALLBACK _GSocket_Internal_WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, @@ -834,6 +870,7 @@ LRESULT CALLBACK _GSocket_Internal_WinProc(HWND hWnd, GSocket *socket; GSocketEvent event; GSocketCallback cback; + char *data; if (uMsg >= WM_USER && uMsg <= (WM_USER + MAXSOCKETS - 1)) { @@ -841,6 +878,7 @@ LRESULT CALLBACK _GSocket_Internal_WinProc(HWND hWnd, socket = socketList[(uMsg - WM_USER)]; event = -1; cback = NULL; + data = NULL; /* Check that the socket still exists (it has not been * destroyed) and for safety, check that the m_fd field @@ -865,7 +903,15 @@ LRESULT CALLBACK _GSocket_Internal_WinProc(HWND hWnd, } if (event != -1) + { cback = socket->m_cbacks[event]; + data = socket->m_data[event]; + + if (event == GSOCK_LOST) + socket->m_detected = GSOCK_LOST_FLAG; + else + socket->m_detected |= (1 << event); + } } /* OK, we can now leave the critical section because we have @@ -875,7 +921,7 @@ LRESULT CALLBACK _GSocket_Internal_WinProc(HWND hWnd, LeaveCriticalSection(&critical); if (cback != NULL) - (cback)(socket, event, socket->m_data[event]); + (cback)(socket, event, data); return (LRESULT) 0; } @@ -928,42 +974,20 @@ GSocketError _GSocket_Output_Timeout(GSocket *socket) int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size) { - int ret; - - ret = recv(socket->m_fd, buffer, size, 0); - - if (ret == SOCKET_ERROR) - { - if (WSAGetLastError() != WSAEWOULDBLOCK) - socket->m_error = GSOCK_IOERR; - else - socket->m_error = GSOCK_WOULDBLOCK; - - return -1; - } - - return ret; + return recv(socket->m_fd, buffer, size, 0); } int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size) { struct sockaddr from; - SOCKLEN_T fromlen; + SOCKLEN_T fromlen = sizeof(from); int ret; - - fromlen = sizeof(from); + GSocketError err; ret = recvfrom(socket->m_fd, buffer, size, 0, &from, &fromlen); if (ret == SOCKET_ERROR) - { - if (WSAGetLastError() != WSAEWOULDBLOCK) - socket->m_error = GSOCK_IOERR; - else - socket->m_error = GSOCK_WOULDBLOCK; - - return -1; - } + return SOCKET_ERROR; /* Translate a system address into a GSocket address */ if (!socket->m_peer) @@ -975,10 +999,12 @@ int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size) return -1; } } - if (_GAddress_translate_from(socket->m_peer, &from, fromlen) != GSOCK_NOERROR) + err = _GAddress_translate_from(socket->m_peer, &from, fromlen); + if (err != GSOCK_NOERROR) { - socket->m_error = GSOCK_MEMERR; GAddress_destroy(socket->m_peer); + socket->m_peer = NULL; + socket->m_error = err; return -1; } @@ -987,26 +1013,14 @@ int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size) int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size) { - int ret; - - ret = send(socket->m_fd, buffer, size, 0); - - if (ret == SOCKET_ERROR) - { - if (WSAGetLastError() != WSAEWOULDBLOCK) - socket->m_error = GSOCK_IOERR; - else - socket->m_error = GSOCK_WOULDBLOCK; - - return -1; - } - return ret; + return send(socket->m_fd, buffer, size, 0); } int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size) { struct sockaddr *addr; int len, ret; + GSocketError err; if (!socket->m_peer) { @@ -1014,9 +1028,10 @@ int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size) return -1; } - if (!_GAddress_translate_to(socket->m_peer, &addr, &len)) + err = _GAddress_translate_to(socket->m_peer, &addr, &len); + if (err != GSOCK_NOERROR) { - socket->m_error = GSOCK_MEMERR; + socket->m_error = err; return -1; } @@ -1025,15 +1040,6 @@ int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size) /* Frees memory allocated by _GAddress_translate_to */ free(addr); - if (ret == SOCKET_ERROR) - { - if (WSAGetLastError() != WSAEWOULDBLOCK) - socket->m_error = GSOCK_IOERR; - else - socket->m_error = GSOCK_WOULDBLOCK; - - return -1; - } return ret; } @@ -1189,6 +1195,7 @@ GSocketError _GAddress_translate_to(GAddress *address, GSocketError _GAddress_Init_INET(GAddress *address) { + address->m_len = sizeof(struct sockaddr_in); address->m_addr = (struct sockaddr *) malloc(address->m_len); if (address->m_addr == NULL) { @@ -1196,11 +1203,10 @@ GSocketError _GAddress_Init_INET(GAddress *address) return GSOCK_MEMERR; } - address->m_len = sizeof(struct sockaddr_in); address->m_family = GSOCK_INET; address->m_realfamily = PF_INET; ((struct sockaddr_in *)address->m_addr)->sin_family = AF_INET; - ((struct sockaddr_in *)address->m_addr)->sin_addr.s_addr = INADDR_ANY; + ((struct sockaddr_in *)address->m_addr)->sin_addr.s_addr = INADDR_NONE; return GSOCK_NOERROR; } @@ -1217,7 +1223,7 @@ GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname) addr = &(((struct sockaddr_in *)address->m_addr)->sin_addr); addr->s_addr = inet_addr(hostname); - + /* If it is a numeric host name, convert it now */ if (addr->s_addr == INADDR_NONE) { @@ -1264,7 +1270,7 @@ GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port, address->m_error = GSOCK_INVPORT; return GSOCK_INVOP; } - + se = getservbyname(port, protocol); if (!se) { @@ -1294,7 +1300,7 @@ GSocketError GAddress_INET_SetPort(GAddress *address, unsigned short port) assert(address != NULL); CHECK_ADDRESS(address, INET, GSOCK_INVADDR); - + addr = (struct sockaddr_in *)address->m_addr; addr->sin_port = htons(port); @@ -1307,7 +1313,7 @@ GSocketError GAddress_INET_GetHostName(GAddress *address, char *hostname, size_t char *addr_buf; struct sockaddr_in *addr; - assert(address != NULL); + assert(address != NULL); CHECK_ADDRESS(address, INET, GSOCK_INVADDR); addr = (struct sockaddr_in *)address->m_addr; @@ -1329,8 +1335,8 @@ unsigned long GAddress_INET_GetHostAddress(GAddress *address) { struct sockaddr_in *addr; - assert(address != NULL); - CHECK_ADDRESS(address, INET, 0); + assert(address != NULL); + CHECK_ADDRESS(address, INET, 0); addr = (struct sockaddr_in *)address->m_addr; @@ -1341,8 +1347,8 @@ unsigned short GAddress_INET_GetPort(GAddress *address) { struct sockaddr_in *addr; - assert(address != NULL); - CHECK_ADDRESS(address, INET, 0); + assert(address != NULL); + CHECK_ADDRESS(address, INET, 0); addr = (struct sockaddr_in *)address->m_addr; return ntohs(addr->sin_port); @@ -1375,11 +1381,15 @@ GSocketError GAddress_UNIX_GetPath(GAddress *address, char *path, size_t sbuf) return GSOCK_INVADDR; } +#else /* !wxUSE_SOCKETS */ -#endif /* defined(__GSOCKET_STANDALONE__) || defined(wxUSE_SOCKETS) */ - - +/* + * translation unit shouldn't be empty, so include this typedef to make the + * compiler (VC++ 6.0, for example) happy + */ +typedef (*wxDummy)(); +#endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */ /* Diferencias con la version Unix: * - El descriptor es SOCKET y no int @@ -1389,9 +1399,7 @@ GSocketError GAddress_UNIX_GetPath(GAddress *address, char *path, size_t sbuf) * - inet_addr en lugar de inet_aton * - Codigo de inicializacion y terminacion para inicializar y * terminar WinSocket y para la ventana interna. - * - SetTimeout en la version MSW simplemente guarda el valor en - * socket.m_timeout, por tanto no hay necesidad de llamar a - * SetTimeout cada vez que se crea realmente un socket (no - * un gsocket). - * - Lo mismo para SetNonBlocking. + * - SetTimeout, SetNonBlocking y la implementacion de los + * timeouts eran bastante diferentes, pero ahora se han + * hecho en la version Unix igual que en esta. */