From 74c481d11721fb42343c6b79996478a2ebacde3a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 25 Jul 2004 17:06:01 +0000 Subject: [PATCH] replaced my recent GSocket_SetReuseAddr() addition with GSocket_SetReusable() from the patch 992473; it also adds and documents wxSOCKET_REUSEADDR flag git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@28494 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/latex/wx/socket.tex | 10 +++++ include/wx/gsocket.h | 10 ++++- include/wx/msw/gsockmsw.h | 1 + include/wx/socket.h | 3 +- src/common/socket.cpp | 5 +++ src/unix/gsocket.c | 77 +++++++++++++++++++++------------------ 6 files changed, 69 insertions(+), 37 deletions(-) diff --git a/docs/latex/wx/socket.tex b/docs/latex/wx/socket.tex index 1c8d64aa73..e8741147d0 100644 --- a/docs/latex/wx/socket.tex +++ b/docs/latex/wx/socket.tex @@ -593,6 +593,7 @@ The following flags can be used: \twocolitem{{\bf wxSOCKET\_NOWAIT}}{Read/write as much data as possible and return immediately.} \twocolitem{{\bf wxSOCKET\_WAITALL}}{Wait for all required data to be read/written unless an error occurs.} \twocolitem{{\bf wxSOCKET\_BLOCK}}{Block the GUI (do not yield) while reading/writing data.} +\twocolitem{{\bf wxSOCKET\_REUSEADDR}}{Allows the use of an in-use port (wxServerSocket only)} \end{twocollist} A brief overview on how to use these flags follows. @@ -626,6 +627,13 @@ during IO calls, so the GUI will remain blocked until the operation completes. If it is not used, then the application must take extra care to avoid unwanted reentrance. +The {\bf wxSOCKET\_REUSEADDR} flag controls the use of the SO_REUSEADDR standard +setsockopt() flag. This flag allows the socket to bind to a port that is already in use. +This is mostly used on UNIX-based systems to allow rapid starting and stopping of a server - +otherwise you may have to wait several minutes for the port to become available. +This option can have suprising platform dependent behavior, check the documentation for +your platforms implementation of setsockopt(). + So: {\bf wxSOCKET\_NONE} will try to read at least SOME data, no matter how much. @@ -639,6 +647,8 @@ the data. {\bf wxSOCKET\_BLOCK} has nothing to do with the previous flags and it controls whether the GUI blocks. +(\bf wxSOCKET\_REUSEADDR} controls special platform-specific behavior for wxServerSocket. + % % SetNotify % diff --git a/include/wx/gsocket.h b/include/wx/gsocket.h index 3b0faf040b..3301e79511 100644 --- a/include/wx/gsocket.h +++ b/include/wx/gsocket.h @@ -235,6 +235,15 @@ GSocket *GSocket_WaitConnection(GSocket *socket); */ GSocketError GSocket_Connect(GSocket *socket, GSocketStream stream); +/* GSocket_SetReusable: +* Simply sets the m_resuable flag on the socket. GSocket_SetServer will +* make the appropriate setsockopt() call. +* Implemented as a GSocket function because clients (ie, wxSocketServer) +* don't have access to the GSocket struct information. +* Returns TRUE if the flag was set correctly, FALSE if an error occured +* (ie, if the parameter was NULL) +*/ +int GSocket_SetReusable(GSocket *socket); /* Datagram sockets */ @@ -277,7 +286,6 @@ GSocketError GSocket_GetSockOpt(GSocket *socket, int level, int optname, GSocketError GSocket_SetSockOpt(GSocket *socket, int level, int optname, const void *optval, int optlen); -GSocketError GSocket_SetReuseAddr(GSocket *socket); void GSocket_Streamed(GSocket *socket); void GSocket_Unstreamed(GSocket *socket); diff --git a/include/wx/msw/gsockmsw.h b/include/wx/msw/gsockmsw.h index a000ababea..3961fc9429 100644 --- a/include/wx/msw/gsockmsw.h +++ b/include/wx/msw/gsockmsw.h @@ -50,6 +50,7 @@ struct _GSocket int m_stream; int m_oriented; int m_establishing; + int m_reusable; struct timeval m_timeout; /* Callbacks */ diff --git a/include/wx/socket.h b/include/wx/socket.h index 90e99f7f62..03cc2fb1bd 100644 --- a/include/wx/socket.h +++ b/include/wx/socket.h @@ -74,7 +74,8 @@ enum wxSOCKET_NONE = 0, wxSOCKET_NOWAIT = 1, wxSOCKET_WAITALL = 2, - wxSOCKET_BLOCK = 4 + wxSOCKET_BLOCK = 4, + wxSOCKET_REUSEADDR = 8 }; enum wxSocketType diff --git a/src/common/socket.cpp b/src/common/socket.cpp index 848e383c4b..043eb9a07d 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -1068,6 +1068,11 @@ wxSocketServer::wxSocketServer(wxSockAddress& addr_man, // Setup the socket as server GSocket_SetLocal(m_socket, addr_man.GetAddress()); + + if (GetFlags() & wxSOCKET_REUSEADDR) { + GSocket_SetReusable(m_socket); + } + if (GSocket_SetServer(m_socket) != GSOCK_NOERROR) { GSocket_destroy(m_socket); diff --git a/src/unix/gsocket.c b/src/unix/gsocket.c index 28b5f54307..6de6e941a8 100644 --- a/src/unix/gsocket.c +++ b/src/unix/gsocket.c @@ -197,7 +197,7 @@ void GSocket_SetGUIFunctions(struct GSocketGUIFunctionsTable *guifunc) { gs_gui_functions = guifunc; } - + int GSocket_Init(void) { if (gs_gui_functions) @@ -437,11 +437,11 @@ GAddress *GSocket_GetPeer(GSocket *socket) * Sets up this socket as a server. The local address must have been * set with GSocket_SetLocal() before GSocket_SetServer() is called. * Returns GSOCK_NOERROR on success, one of the following otherwise: - * + * * Error codes: * GSOCK_INVSOCK - the socket is in use. * GSOCK_INVADDR - the local address has not been set. - * GSOCK_IOERR - low-level error. + * GSOCK_IOERR - low-level error. */ GSocketError GSocket_SetServer(GSocket *sck) { @@ -483,6 +483,12 @@ GSocketError GSocket_SetServer(GSocket *sck) #endif _GSocket_Enable_Events(sck); + /* allow a socket to re-bind if the socket is in the TIME_WAIT + state after being previously closed. + */ + if (sck->m_reusable) + setsockopt(socket->m_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&arg, sizeof(u_long)); + /* Bind to the local address, * retrieve the actual address bound, * and listen up to 5 connections. @@ -511,7 +517,7 @@ GSocketError GSocket_SetServer(GSocket *sck) * GSOCK_TIMEDOUT - timeout, no incoming connections. * GSOCK_WOULDBLOCK - the call would block and the socket is nonblocking. * GSOCK_MEMERR - couldn't allocate memory. - * GSOCK_IOERR - low-level error. + * GSOCK_IOERR - low-level error. */ GSocket *GSocket_WaitConnection(GSocket *socket) { @@ -594,6 +600,16 @@ GSocket *GSocket_WaitConnection(GSocket *socket) return connection; } +int GSocket_SetReusable(GSocket *socket) +{ + /* socket must not be null, and must not be in use/already bound */ + if (NULL != socket && socket->m_fd == INVALID_SOCKET) { + socket->m_reusable = TRUE; + return TRUE; + } + return FALSE; +} + /* Client specific parts */ /* GSocket_Connect: @@ -617,7 +633,7 @@ GSocket *GSocket_WaitConnection(GSocket *socket) * GSOCK_TIMEDOUT - timeout, the connection failed. * GSOCK_WOULDBLOCK - connection in progress (nonblocking sockets only) * GSOCK_MEMERR - couldn't allocate memory. - * GSOCK_IOERR - low-level error. + * GSOCK_IOERR - low-level error. */ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream) { @@ -803,7 +819,7 @@ int GSocket_Read(GSocket *socket, char *buffer, int size) /* Disable events during query of socket status */ _GSocket_Disable(socket, GSOCK_INPUT); - + /* If the socket is blocking, wait for data (with a timeout) */ if (_GSocket_Input_Timeout(socket) == GSOCK_TIMEDOUT) /* We no longer return here immediately, otherwise socket events would not be re-enabled! */ @@ -815,7 +831,7 @@ int GSocket_Read(GSocket *socket, char *buffer, int size) else ret = _GSocket_Recv_Dgram(socket, buffer, size); } - + if (ret == -1) { if (errno == EWOULDBLOCK) @@ -823,19 +839,19 @@ int GSocket_Read(GSocket *socket, char *buffer, int size) else socket->m_error = GSOCK_IOERR; } - + /* Enable events again now that we are done processing */ _GSocket_Enable(socket, GSOCK_INPUT); - + return ret; } int GSocket_Write(GSocket *socket, const char *buffer, int size) -{ +{ int ret; assert(socket != NULL); - + GSocket_Debug(( "GSocket_Write #1, size %d\n", size )); if (socket->m_fd == INVALID_SOCKET || socket->m_server) @@ -857,7 +873,7 @@ int GSocket_Write(GSocket *socket, const char *buffer, int size) ret = _GSocket_Send_Stream(socket, buffer, size); else ret = _GSocket_Send_Dgram(socket, buffer, size); - + GSocket_Debug(( "GSocket_Write #4, size %d\n", size )); if (ret == -1) @@ -881,7 +897,7 @@ int GSocket_Write(GSocket *socket, const char *buffer, int size) _GSocket_Enable(socket, GSOCK_OUTPUT); return -1; } - + GSocket_Debug(( "GSocket_Write #5, size %d ret %d\n", size, ret )); return ret; @@ -959,7 +975,7 @@ GSocketEventFlags GSocket_Select(GSocket *socket, GSocketEventFlags flags) { socket->m_detected = GSOCK_LOST_FLAG; socket->m_establishing = FALSE; - + /* LOST event: Abort any further processing */ return (GSOCK_LOST_FLAG & flags); } @@ -1064,7 +1080,7 @@ GSocketError GSocket_GetError(GSocket *socket) * operation, there is still data available, the callback function will * be called again. * GSOCK_OUTPUT: - * The socket is available for writing. That is, the next write call + * The socket is available for writing. That is, the next write call * won't block. This event is generated only once, when the connection is * first established, and then only if a call failed with GSOCK_WOULDBLOCK, * when the output buffer empties again. This means that the app should @@ -1134,25 +1150,16 @@ GSocketError GSocket_GetSockOpt(GSocket *socket, int level, int optname, return GSOCK_OPTERR; } -GSocketError GSocket_SetSockOpt(GSocket *socket, int level, int optname, +GSocketError GSocket_SetSockOpt(GSocket *socket, int level, int optname, const void *optval, int optlen) { if (setsockopt(socket->m_fd, level, optname, optval, optlen) == 0) { - return GSOCK_NOERROR; + return GSOCK_NOERROR; } return GSOCK_OPTERR; } -GSocketError GSocket_SetReuseAddr(GSocket *socket) -{ - /* allow a socket to re-bind if the socket is in the TIME_WAIT - state after being previously closed. - */ - u_long arg = 1; - setsockopt(socket->m_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&arg, sizeof(u_long)); -} - void GSocket_Streamed(GSocket *socket) { socket->m_stream = TRUE; @@ -1702,7 +1709,7 @@ GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port, address->m_error = GSOCK_INVPORT; return GSOCK_INVPORT; } - + se = getservbyname(port, protocol); if (!se) { @@ -1734,7 +1741,7 @@ GSocketError GAddress_INET_SetPort(GAddress *address, unsigned short port) assert(address != NULL); CHECK_ADDRESS(address, INET); - + addr = (struct sockaddr_in *)address->m_addr; addr->sin_port = htons(port); @@ -1747,7 +1754,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); addr = (struct sockaddr_in *)address->m_addr; @@ -1769,8 +1776,8 @@ unsigned long GAddress_INET_GetHostAddress(GAddress *address) { struct sockaddr_in *addr; - assert(address != NULL); - CHECK_ADDRESS_RETVAL(address, INET, 0); + assert(address != NULL); + CHECK_ADDRESS_RETVAL(address, INET, 0); addr = (struct sockaddr_in *)address->m_addr; @@ -1781,8 +1788,8 @@ unsigned short GAddress_INET_GetPort(GAddress *address) { struct sockaddr_in *addr; - assert(address != NULL); - CHECK_ADDRESS_RETVAL(address, INET, 0); + assert(address != NULL); + CHECK_ADDRESS_RETVAL(address, INET, 0); addr = (struct sockaddr_in *)address->m_addr; return ntohs(addr->sin_port); @@ -1819,9 +1826,9 @@ GSocketError GAddress_UNIX_SetPath(GAddress *address, const char *path) { struct sockaddr_un *addr; - assert(address != NULL); + assert(address != NULL); - CHECK_ADDRESS(address, UNIX); + CHECK_ADDRESS(address, UNIX); addr = ((struct sockaddr_un *)address->m_addr); strncpy(addr->sun_path, path, UNIX_SOCK_PATHLEN); -- 2.45.2