From b1828e0958fd4260e7065f1ae421ff5a4fa9351c Mon Sep 17 00:00:00 2001 From: Daniel Collins Date: Thu, 8 Sep 2011 18:28:01 +0000 Subject: [PATCH] Implemented proper SO_REUSEADDR support and fixed getsockopt to return proper value when SOL_SOCKET/SO_BROADCAST is requested. --- src/ipxwrapper.h | 1 + src/router.c | 31 ++++++++++++++++++++++++++++--- src/router.h | 9 +++------ src/winsock.c | 34 ++++++++++++++++++++++++++++++++-- 4 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/ipxwrapper.h b/src/ipxwrapper.h index 0c5b2ec..8aac5a6 100644 --- a/src/ipxwrapper.h +++ b/src/ipxwrapper.h @@ -39,6 +39,7 @@ #define IPX_SEND (int)(1<<3) #define IPX_RECV (int)(1<<4) #define IPX_EX_BOUND (int)(1<<5) +#define IPX_REUSE (int)(1<<6) #define RETURN(...) \ unlock_sockets();\ diff --git a/src/router.c b/src/router.c index 327dc5a..600288b 100644 --- a/src/router.c +++ b/src/router.c @@ -240,7 +240,7 @@ DWORD router_main(void *arg) { return 0; } -int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast) { +int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast, BOOL reuse) { /* Network number 00:00:00:00 is specified as the "current" network, this code * treats it as a wildcard when used for the network OR node numbers. * @@ -323,13 +323,13 @@ int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct } addr->sa_socket = htons(s); - }else if(addr->sa_family != AF_IPX_SHARE) { + }else{ /* Test if any bound socket is using the requested socket number. */ struct router_addr *a = router->addrs; while(a) { - if(a->addr.sa_socket == addr->sa_socket) { + if(a->addr.sa_socket == addr->sa_socket && (!a->reuse || !reuse)) { log_printf("bind failed: requested socket in use"); LeaveCriticalSection(&(router->crit_sec)); @@ -356,6 +356,7 @@ int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct new_addr->ws_socket = sock; new_addr->control_socket = control; new_addr->filter_ptype = -1; + new_addr->reuse = reuse; new_addr->next = NULL; router->addrs = new_addr; @@ -431,3 +432,27 @@ void router_set_filter(struct router_vars *router, SOCKET control, SOCKET sock, LeaveCriticalSection(&(router->crit_sec)); } + +int router_set_reuse(struct router_vars *router, SOCKET control, SOCKET sock, BOOL reuse) { + EnterCriticalSection(&(router->crit_sec)); + + struct router_addr *addr = router_get(router, control, sock); + if(addr) { + struct router_addr *test = router->addrs; + + while(test) { + if(addr != test && memcmp(&(addr->addr), &(test->addr), sizeof(struct sockaddr_ipx)) == 0 && !reuse) { + /* Refuse to disable SO_REUSEADDR when another binding for the same address exists */ + LeaveCriticalSection(&(router->crit_sec)); + return 0; + } + + test = test->next; + } + + addr->reuse = reuse; + } + + LeaveCriticalSection(&(router->crit_sec)); + return 1; +} diff --git a/src/router.h b/src/router.h index 3d8c939..0c838d2 100644 --- a/src/router.h +++ b/src/router.h @@ -23,11 +23,6 @@ #include #include -/* Special address family for use when binding AF_IPX sockets, allows multiple - * sockets to share the same address. -*/ -#define AF_IPX_SHARE 42 - /* Represents a bound IPX address */ struct router_addr { struct sockaddr_ipx addr; @@ -36,6 +31,7 @@ struct router_addr { SOCKET ws_socket; /* Application socket */ SOCKET control_socket; /* Control socket */ int filter_ptype; /* Packet type filter, negative to disable */ + BOOL reuse; /* SO_REUSEADDR */ struct router_addr *next; }; @@ -63,9 +59,10 @@ void router_destroy(struct router_vars *router); DWORD router_main(void *arg); -int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast); +int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast, BOOL reuse); void router_set_port(struct router_vars *router, SOCKET control, SOCKET sock, uint16_t port); void router_unbind(struct router_vars *router, SOCKET control, SOCKET sock); void router_set_filter(struct router_vars *router, SOCKET control, SOCKET sock, int ptype); +int router_set_reuse(struct router_vars *router, SOCKET control, SOCKET sock, BOOL reuse); #endif /* !IPXWRAPPER_ROUTER_H */ diff --git a/src/winsock.c b/src/winsock.c index 94f0d58..63a22c2 100644 --- a/src/winsock.c +++ b/src/winsock.c @@ -190,7 +190,7 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen) { RETURN_WSA(WSAEINVAL, -1); } - if(router_bind(router, 0, fd, &ipxaddr, &(ptr->nic_bcast)) == -1) { + if(router_bind(router, 0, fd, &ipxaddr, &(ptr->nic_bcast), ptr->flags & IPX_REUSE ? TRUE : FALSE) == -1) { RETURN(-1); } @@ -395,6 +395,7 @@ int PASCAL WSARecvEx(SOCKET fd, char *buf, int len, int *flags) { int WSAAPI getsockopt(SOCKET fd, int level, int optname, char FAR *optval, int FAR *optlen) { int* intval = (int*)optval; + BOOL *bval = (BOOL*)optval; ipx_socket *ptr = get_socket(fd); @@ -473,6 +474,22 @@ int WSAAPI getsockopt(SOCKET fd, int level, int optname, char FAR *optval, int F RETURN_WSA(WSAENOPROTOOPT, -1); } + if(level == SOL_SOCKET) { + if(optname == SO_BROADCAST) { + CHECK_OPTLEN(sizeof(BOOL)); + + *bval = ptr->flags & IPX_BROADCAST ? TRUE : FALSE; + RETURN(0); + } + + if(optname == SO_REUSEADDR) { + CHECK_OPTLEN(sizeof(BOOL)); + + *bval = ptr->flags & IPX_REUSE ? TRUE : FALSE; + RETURN(0); + } + } + unlock_sockets(); } @@ -514,12 +531,25 @@ int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval, if(level == SOL_SOCKET) { if(optname == SO_BROADCAST) { - if(*bval == TRUE) { + if(*bval) { sockptr->flags |= IPX_BROADCAST; }else{ sockptr->flags &= ~IPX_BROADCAST; } + RETURN(0); + }else if(optname == SO_REUSEADDR) { + if(!router_set_reuse(router, 0, fd, *bval)) { + WSASetLastError(WSAEINVAL); + RETURN(-1); + } + + if(*bval) { + sockptr->flags |= IPX_REUSE; + }else{ + sockptr->flags &= ~IPX_REUSE; + } + RETURN(0); } }