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
This commit is contained in:
Vadim Zeitlin 2004-07-25 17:06:01 +00:00
parent 733a25f0f4
commit 74c481d117
6 changed files with 69 additions and 37 deletions

View File

@ -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
%

View File

@ -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);

View File

@ -50,6 +50,7 @@ struct _GSocket
int m_stream;
int m_oriented;
int m_establishing;
int m_reusable;
struct timeval m_timeout;
/* Callbacks */

View File

@ -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

View File

@ -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);

View File

@ -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);