1
0
mirror of https://github.com/solemnwarning/ipxwrapper synced 2024-12-30 16:45:37 +01:00

Implemented proper SO_REUSEADDR support and fixed getsockopt to return proper value when SOL_SOCKET/SO_BROADCAST is requested.

This commit is contained in:
Daniel Collins 2011-09-08 18:28:01 +00:00
parent 48b141d7e9
commit b1828e0958
4 changed files with 64 additions and 11 deletions

View File

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

View File

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

View File

@ -23,11 +23,6 @@
#include <wsipx.h>
#include <stdint.h>
/* 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 */

View File

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