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

Implemented IPX_RECEIVE_BROADCAST option, updated router/rclient API and added proper checks when receiving broadcast packets to the router main loop.

This commit is contained in:
Daniel Collins 2011-09-17 23:47:31 +00:00
parent 646ab3b011
commit fd555ce7c2
5 changed files with 65 additions and 49 deletions

View File

@ -85,5 +85,5 @@ src/dpwsockx_stubs.s: src/dpwsockx_stubs.txt
src/%_stubs.o: src/%_stubs.s
nasm -f win32 -o $@ $<
src/%.o: src/%.c src/ipxwrapper.h src/config.h src/common.h
src/%.o: src/%.c src/ipxwrapper.h src/config.h src/common.h src/router.h
$(CC) $(CFLAGS) -c -o $@ $<

View File

@ -38,6 +38,7 @@
#define IPX_RECV (int)(1<<4)
#define IPX_REUSE (int)(1<<6)
#define IPX_CONNECTED (int)(1<<7)
#define IPX_RECV_BCAST (int)(1<<8)
#define RETURN(...) \
unlock_sockets();\

View File

@ -287,8 +287,8 @@ DWORD router_main(void *arg) {
if(
ra->local_port &&
(ra->filter_ptype < 0 || ra->filter_ptype == packet->ptype) &&
(memcmp(packet->dest_net, ra->addr.sa_netnum, 4) == 0 || memcmp(packet->dest_net, f6, 4) == 0) &&
(memcmp(packet->dest_node, ra->addr.sa_nodenum, 6) == 0 || memcmp(packet->dest_node, f6, 6) == 0) &&
(memcmp(packet->dest_net, ra->addr.sa_netnum, 4) == 0 || (memcmp(packet->dest_net, f6, 4) == 0 && (ra->flags & IPX_BROADCAST || !global_conf.w95_bug) && ra->flags & IPX_RECV_BCAST)) &&
(memcmp(packet->dest_node, ra->addr.sa_nodenum, 6) == 0 || (memcmp(packet->dest_node, f6, 6) == 0 && (ra->flags & IPX_BROADCAST || !global_conf.w95_bug) && ra->flags & IPX_RECV_BCAST)) &&
packet->dest_socket == ra->addr.sa_socket &&
/* Check source IP is within correct subnet */
@ -314,7 +314,7 @@ DWORD router_main(void *arg) {
return 0;
}
static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast, BOOL reuse) {
static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast, int flags) {
/* 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.
*
@ -406,7 +406,7 @@ static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock,
struct router_addr *a = router->addrs;
while(a) {
if(a->addr.sa_socket == addr->sa_socket && (!a->reuse || !reuse)) {
if(a->addr.sa_socket == addr->sa_socket && (!(a->flags & IPX_REUSE) || !(flags & IPX_REUSE))) {
log_printf("bind failed: requested socket in use");
LeaveCriticalSection(&(router->crit_sec));
@ -433,7 +433,7 @@ static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock,
new_addr->ws_socket = sock;
new_addr->control_socket = control;
new_addr->filter_ptype = -1;
new_addr->reuse = reuse;
new_addr->flags = flags;
new_addr->ipaddr = iface_ipaddr;
new_addr->netmask = iface_netmask;
new_addr->next = router->addrs;
@ -512,28 +512,30 @@ static void router_set_filter(struct router_vars *router, SOCKET control, SOCKET
LeaveCriticalSection(&(router->crit_sec));
}
static int router_set_reuse(struct router_vars *router, SOCKET control, SOCKET sock, BOOL reuse) {
static int router_set_flags(struct router_vars *router, SOCKET control, SOCKET sock, int flags) {
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;
}
if(addr->flags & IPX_REUSE && !(flags & IPX_REUSE)) {
struct router_addr *test = router->addrs;
test = test->next;
while(test) {
if(addr != test && memcmp(&(addr->addr), &(test->addr), sizeof(struct sockaddr_ipx)) == 0) {
/* Refuse to disable SO_REUSEADDR when another binding for the same address exists */
LeaveCriticalSection(&(router->crit_sec));
return WSAEINVAL;
}
test = test->next;
}
}
addr->reuse = reuse;
addr->flags = flags;
}
LeaveCriticalSection(&(router->crit_sec));
return 1;
return ERROR_SUCCESS;
}
static BOOL router_set_remote(struct router_vars *router, SOCKET control, SOCKET sock, const struct sockaddr_ipx *addr) {
@ -579,11 +581,8 @@ static BOOL router_handle_call(struct router_vars *router, int sock, struct rout
break;
}
case rc_reuse: {
if(!router_set_reuse(router, sock, call->sock, call->arg_int)) {
ret.err_code = WSAEINVAL;
}
case rc_flags: {
ret.err_code = router_set_flags(router, sock, call->sock, call->arg_int);
break;
}
@ -879,14 +878,14 @@ BOOL rclient_set_filter(struct rclient *rclient, SOCKET sock, int ptype) {
return FALSE;
}
BOOL rclient_set_reuse(struct rclient *rclient, SOCKET sock, BOOL reuse) {
BOOL rclient_set_flags(struct rclient *rclient, SOCKET sock, int flags) {
if(rclient->sock != -1) {
struct router_call call;
struct router_ret ret;
call.call = rc_reuse;
call.call = rc_flags;
call.sock = sock;
call.arg_int = reuse;
call.arg_int = flags;
if(!rclient_do(rclient, &call, &ret)) {
return FALSE;
@ -895,11 +894,18 @@ BOOL rclient_set_reuse(struct rclient *rclient, SOCKET sock, BOOL reuse) {
if(ret.err_code == ERROR_SUCCESS) {
return TRUE;
}else{
WSASetLastError(WSAEINVAL);
WSASetLastError(ret.err_code);
return FALSE;
}
}else if(rclient->router) {
router_set_reuse(rclient->router, 0, sock, reuse);
int err = router_set_flags(rclient->router, 0, sock, flags);
if(err == ERROR_SUCCESS) {
return TRUE;
}else{
WSASetLastError(err);
return FALSE;
}
return TRUE;
}

View File

@ -31,7 +31,7 @@ struct router_call {
rc_unbind,
rc_port,
rc_filter,
rc_reuse,
rc_flags,
rc_remote
} call;
@ -56,7 +56,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 */
int flags;
/* Address of IP interface */
uint32_t ipaddr;
@ -118,11 +118,11 @@ BOOL rclient_init(struct rclient *rclient);
BOOL rclient_start(struct rclient *rclient);
void rclient_stop(struct rclient *rclient);
BOOL rclient_bind(struct rclient *rclient, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast, BOOL reuse);
BOOL rclient_bind(struct rclient *rclient, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast, int flags);
BOOL rclient_unbind(struct rclient *rclient, SOCKET sock);
BOOL rclient_set_port(struct rclient *rclient, SOCKET sock, uint16_t port);
BOOL rclient_set_filter(struct rclient *rclient, SOCKET sock, int ptype);
BOOL rclient_set_reuse(struct rclient *rclient, SOCKET sock, BOOL reuse);
BOOL rclient_set_flags(struct rclient *rclient, SOCKET sock, int flags);
BOOL rclient_set_remote(struct rclient *rclient, SOCKET sock, const struct sockaddr_ipx *addr);
#endif /* !IPXWRAPPER_ROUTER_H */

View File

@ -160,7 +160,7 @@ SOCKET WSAAPI socket(int af, int type, int protocol) {
return -1;
}
nsock->flags = IPX_SEND | IPX_RECV;
nsock->flags = IPX_SEND | IPX_RECV | IPX_RECV_BCAST;
nsock->s_ptype = (protocol ? NSPROTO_IPX - protocol : 0);
lock_sockets();
@ -544,6 +544,18 @@ int WSAAPI getsockopt(SOCKET fd, int level, int optname, char FAR *optval, int F
return r_getsockopt(fd, level, optname, optval, optlen);
}
#define SET_FLAG(flag, state) \
if(state) { \
sockptr->flags |= flag; \
}else{ \
sockptr->flags &= flag; \
}
#define RC_SET_FLAG(flag, state) \
if(sockptr->flags & IPX_BOUND && !rclient_set_flags(&g_rclient, fd, (sockptr->flags & ~(flag)) | ((state) ? (flag) : 0))) { \
RETURN(-1); \
}
int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval, int optlen) {
int *intval = (int*)optval;
BOOL *bval = (BOOL*)optval;
@ -578,28 +590,25 @@ int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval,
RETURN(0);
}
if(optname == IPX_RECEIVE_BROADCAST) {
RC_SET_FLAG(IPX_RECV_BCAST, *bval);
SET_FLAG(IPX_RECV_BCAST, *bval);
RETURN(0);
}
RETURN_WSA(WSAENOPROTOOPT, -1);
}
if(level == SOL_SOCKET) {
if(optname == SO_BROADCAST) {
if(*bval) {
sockptr->flags |= IPX_BROADCAST;
}else{
sockptr->flags &= ~IPX_BROADCAST;
}
SET_FLAG(IPX_BROADCAST, *bval);
RETURN(0);
}else if(optname == SO_REUSEADDR) {
if(sockptr->flags & IPX_BOUND && !rclient_set_reuse(&g_rclient, fd, *bval)) {
RETURN(-1);
}
if(*bval) {
sockptr->flags |= IPX_REUSE;
}else{
sockptr->flags &= ~IPX_REUSE;
}
}
if(optname == SO_REUSEADDR) {
RC_SET_FLAG(IPX_REUSE, *bval);
SET_FLAG(IPX_REUSE, *bval);
RETURN(0);
}