From 8e06150325b275e7fabcf57709afe4abd58e1522 Mon Sep 17 00:00:00 2001 From: Daniel Collins Date: Fri, 9 Sep 2011 18:36:52 +0000 Subject: [PATCH] Completed changes to allow for separate router processes. --- src/ipxwrapper.c | 52 +------ src/ipxwrapper.h | 2 +- src/ipxwrapper_stubs.txt | 1 + src/router.c | 287 ++++++++++++++++++++++++++++++++++++++- src/router.h | 24 +++- src/winsock.c | 38 +++--- 6 files changed, 332 insertions(+), 72 deletions(-) diff --git a/src/ipxwrapper.c b/src/ipxwrapper.c index d897707..4ee5fb3 100644 --- a/src/ipxwrapper.c +++ b/src/ipxwrapper.c @@ -47,14 +47,11 @@ HMODULE winsock2_dll = NULL; HMODULE mswsock_dll = NULL; HMODULE wsock32_dll = NULL; -static HANDLE router_thread = NULL; -struct router_vars *router = NULL; +struct rclient g_rclient; static CRITICAL_SECTION sockets_cs; static CRITICAL_SECTION hosts_cs; -static BOOL start_router(void); - #define INIT_CS(cs) if(!init_cs(cs, &initialised_cs)) { return FALSE; } static BOOL init_cs(CRITICAL_SECTION *cs, int *counter) { @@ -73,6 +70,10 @@ BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res) { if(why == DLL_PROCESS_ATTACH) { log_open(); + if(!rclient_init(&g_rclient)) { + return FALSE; + } + winsock2_dll = load_sysdll("ws2_32.dll"); mswsock_dll = load_sysdll("mswsock.dll"); wsock32_dll = load_sysdll("wsock32.dll"); @@ -102,29 +103,11 @@ BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res) { return FALSE; } - if(!start_router()) { + if(!rclient_start(&g_rclient)) { return FALSE; } }else if(why == DLL_PROCESS_DETACH) { - if(router_thread) { - EnterCriticalSection(&(router->crit_sec)); - - router->running = FALSE; - SetEvent(router->wsa_event); - - LeaveCriticalSection(&(router->crit_sec)); - - if(WaitForSingleObject(router_thread, 3000) == WAIT_TIMEOUT) { - log_printf("Router thread didn't exit in 3 seconds, killing"); - TerminateThread(router_thread, 0); - } - - CloseHandle(router_thread); - router_thread = NULL; - - router_destroy(router); - router = NULL; - } + rclient_stop(&g_rclient); WSACleanup(); @@ -203,27 +186,6 @@ void unlock_sockets(void) { LeaveCriticalSection(&sockets_cs); } -/* Initialize and start the router thread */ -static BOOL start_router(void) { - if(!(router = router_init(FALSE))) { - return FALSE; - } - - router_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&router_main, router, 0, NULL); - if(!router_thread) { - log_printf("Failed to create router thread: %s", w32_error(GetLastError())); - - router_destroy(router); - router = NULL; - - return FALSE; - } - - net_fd = router->udp_sock; - - return TRUE; -} - /* Add a host to the hosts list or update an existing one */ void add_host(const unsigned char *net, const unsigned char *node, uint32_t ipaddr) { EnterCriticalSection(&hosts_cs); diff --git a/src/ipxwrapper.h b/src/ipxwrapper.h index 7ccf3bd..f89e3ce 100644 --- a/src/ipxwrapper.h +++ b/src/ipxwrapper.h @@ -103,7 +103,7 @@ extern struct ipx_interface *nics; extern ipx_host *hosts; extern SOCKET net_fd; extern struct reg_global global_conf; -extern struct router_vars *router; +extern struct rclient g_rclient; extern HMODULE winsock2_dll; extern HMODULE mswsock_dll; diff --git a/src/ipxwrapper_stubs.txt b/src/ipxwrapper_stubs.txt index 7efde02..1481108 100644 --- a/src/ipxwrapper_stubs.txt +++ b/src/ipxwrapper_stubs.txt @@ -11,6 +11,7 @@ select listen accept send +connect WSACreateEvent WSAEventSelect WSACloseEvent diff --git a/src/router.c b/src/router.c index 38a4dca..c152864 100644 --- a/src/router.c +++ b/src/router.c @@ -27,6 +27,8 @@ static struct router_addr *router_get(struct router_vars *router, SOCKET control static void router_handle_call(struct router_vars *router, int coff); static void router_drop_client(struct router_vars *router, int coff); +static BOOL rclient_do(struct rclient *rclient, struct router_call *call, struct router_ret *ret); + /* Allocate router_vars structure and initialise all members * Returns NULL on failure */ @@ -330,7 +332,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, BOOL reuse) { +static 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. * @@ -459,7 +461,7 @@ int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct /* Set loopback UDP port of emulation socket in NETWORK BYTE ORDER * Disable recv by setting to zero */ -void router_set_port(struct router_vars *router, SOCKET control, SOCKET sock, uint16_t port) { +static void router_set_port(struct router_vars *router, SOCKET control, SOCKET sock, uint16_t port) { EnterCriticalSection(&(router->crit_sec)); struct router_addr *addr = router_get(router, control, sock); @@ -470,7 +472,7 @@ void router_set_port(struct router_vars *router, SOCKET control, SOCKET sock, ui LeaveCriticalSection(&(router->crit_sec)); } -void router_unbind(struct router_vars *router, SOCKET control, SOCKET sock) { +static void router_unbind(struct router_vars *router, SOCKET control, SOCKET sock) { EnterCriticalSection(&(router->crit_sec)); struct router_addr *addr = router->addrs, *prev = NULL; @@ -512,7 +514,7 @@ static struct router_addr *router_get(struct router_vars *router, SOCKET control /* Set packet type filter for a socket * Disable filter by setting to negative value */ -void router_set_filter(struct router_vars *router, SOCKET control, SOCKET sock, int ptype) { +static void router_set_filter(struct router_vars *router, SOCKET control, SOCKET sock, int ptype) { EnterCriticalSection(&(router->crit_sec)); struct router_addr *addr = router_get(router, control, sock); @@ -523,7 +525,7 @@ 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) { +static 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); @@ -632,3 +634,278 @@ static void router_drop_client(struct router_vars *router, int coff) { closesocket(router->clients[coff].sock); router->clients[coff] = router->clients[--router->client_count]; } + +BOOL rclient_init(struct rclient *rclient) { + rclient->cs_init = FALSE; + rclient->sock = -1; + rclient->router = NULL; + rclient->thread = NULL; + + if(InitializeCriticalSectionAndSpinCount(&(rclient->cs), 0x80000000)) { + rclient->cs_init = TRUE; + }else{ + log_printf("Failed to initialise critical section: %s", w32_error(GetLastError())); + return FALSE; + } + + return TRUE; +} + +/* Connect to the remote router process, spawns local (private) router thread if + * it the remote one isn't running. + * + * Calling when a router is already running is a no-op. +*/ +BOOL rclient_start(struct rclient *rclient) { + if(rclient->sock != -1 || rclient->router) { + return TRUE; + } + + if((rclient->sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + log_printf("Cannot create TCP socket: %s", w32_error(WSAGetLastError())); + return FALSE; + } + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + addr.sin_port = htons(global_conf.udp_port); + + if(connect(rclient->sock, (struct sockaddr*)&addr, sizeof(addr)) == 0) { + return TRUE; + } + + log_printf("Cannot connect to router process: %s", w32_error(WSAGetLastError())); + + closesocket(rclient->sock); + rclient->sock = -1; + + log_printf("Creating private router thread..."); + + if(!(rclient->router = router_init(FALSE))) { + return FALSE; + } + + rclient->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&router_main, rclient->router, 0, NULL); + if(!rclient->thread) { + log_printf("Failed to create router thread: %s", w32_error(GetLastError())); + + router_destroy(rclient->router); + rclient->router = NULL; + + return FALSE; + } + + return TRUE; +} + +/* Disconnect from the router process or stop the private router thread. + * + * Do not attempt to call rclient_start() again without calling rclient_init() + * as the critical section object is deleted. +*/ +void rclient_stop(struct rclient *rclient) { + if(rclient->sock != -1) { + closesocket(rclient->sock); + rclient->sock = -1; + } + + if(rclient->router) { + EnterCriticalSection(&(rclient->router->crit_sec)); + + rclient->router->running = FALSE; + SetEvent(rclient->router->wsa_event); + + LeaveCriticalSection(&(rclient->router->crit_sec)); + + if(WaitForSingleObject(rclient->thread, 3000) == WAIT_TIMEOUT) { + log_printf("Router thread didn't exit in 3 seconds, terminating"); + TerminateThread(rclient->thread, 0); + } + + CloseHandle(rclient->thread); + rclient->thread = NULL; + + router_destroy(rclient->router); + rclient->router = NULL; + } + + if(rclient->cs_init) { + DeleteCriticalSection(&(rclient->cs)); + rclient->cs_init = FALSE; + } +} + +static BOOL rclient_do(struct rclient *rclient, struct router_call *call, struct router_ret *ret) { + EnterCriticalSection(&(rclient->cs)); + + int done, r; + + for(done = 0; done < sizeof(*call);) { + if((r = send(rclient->sock, ((char*)call) + done, sizeof(*call) - done, 0)) == -1) { + log_printf("rclient_do: send error: %s", w32_error(WSAGetLastError())); + + LeaveCriticalSection(&(rclient->cs)); + return FALSE; + } + + done += r; + } + + for(done = 0; done < sizeof(*ret);) { + if((r = recv(rclient->sock, ((char*)ret) + done, sizeof(*ret) - done, 0)) == -1) { + log_printf("rclient_do: recv error: %s", w32_error(WSAGetLastError())); + + LeaveCriticalSection(&(rclient->cs)); + return FALSE; + }else if(r == 0) { + log_printf("rclient_do: Lost connection"); + WSASetLastError(WSAECONNRESET); + + LeaveCriticalSection(&(rclient->cs)); + return FALSE; + } + + done += r; + } + + LeaveCriticalSection(&(rclient->cs)); + return TRUE; +} + +BOOL rclient_bind(struct rclient *rclient, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast, BOOL reuse) { + if(rclient->sock != -1) { + struct router_call call; + struct router_ret ret; + + call.call = rc_bind; + call.sock = sock; + call.arg_addr = *addr; + call.arg_int = reuse; + + if(!rclient_do(rclient, &call, &ret)) { + return FALSE; + } + + if(ret.err_code == ERROR_SUCCESS) { + *addr = ret.ret_addr; + *nic_bcast = ret.ret_u32; + + return TRUE; + }else{ + WSASetLastError(ret.err_code); + return FALSE; + } + }else if(rclient->router) { + return router_bind(rclient->router, 0, sock, addr, nic_bcast, reuse) == 0 ? TRUE: FALSE; + } + + log_printf("rclient_bind: No router?!"); + + WSASetLastError(WSAENETDOWN); + return FALSE; +} + +BOOL rclient_unbind(struct rclient *rclient, SOCKET sock) { + if(rclient->sock != -1) { + struct router_call call; + struct router_ret ret; + + call.call = rc_unbind; + call.sock = sock; + + if(!rclient_do(rclient, &call, &ret)) { + return FALSE; + } + + return TRUE; + }else if(rclient->router) { + router_unbind(rclient->router, 0, sock); + return TRUE; + } + + log_printf("rclient_unbind: No router?!"); + + WSASetLastError(WSAENETDOWN); + return FALSE; +} + +BOOL rclient_set_port(struct rclient *rclient, SOCKET sock, uint16_t port) { + if(rclient->sock != -1) { + struct router_call call; + struct router_ret ret; + + call.call = rc_port; + call.sock = sock; + call.arg_int = port; + + if(!rclient_do(rclient, &call, &ret)) { + return FALSE; + } + + return TRUE; + }else if(rclient->router) { + router_set_port(rclient->router, 0, sock, port); + return TRUE; + } + + log_printf("rclient_set_port: No router?!"); + + WSASetLastError(WSAENETDOWN); + return FALSE; +} + +BOOL rclient_set_filter(struct rclient *rclient, SOCKET sock, int ptype) { + if(rclient->sock != -1) { + struct router_call call; + struct router_ret ret; + + call.call = rc_filter; + call.sock = sock; + call.arg_int = ptype; + + if(!rclient_do(rclient, &call, &ret)) { + return FALSE; + } + + return TRUE; + }else if(rclient->router) { + router_set_filter(rclient->router, 0, sock, ptype); + return TRUE; + } + + log_printf("rclient_set_filter: No router?!"); + + WSASetLastError(WSAENETDOWN); + return FALSE; +} + +BOOL rclient_set_reuse(struct rclient *rclient, SOCKET sock, BOOL reuse) { + if(rclient->sock != -1) { + struct router_call call; + struct router_ret ret; + + call.call = rc_reuse; + call.sock = sock; + call.arg_int = reuse; + + if(!rclient_do(rclient, &call, &ret)) { + return FALSE; + } + + if(ret.err_code == ERROR_SUCCESS) { + return TRUE; + }else{ + WSASetLastError(WSAEINVAL); + return FALSE; + } + }else if(rclient->router) { + router_set_reuse(rclient->router, 0, sock, reuse); + return TRUE; + } + + log_printf("rclient_set_reuse: No router?!"); + + WSASetLastError(WSAENETDOWN); + return FALSE; +} diff --git a/src/router.h b/src/router.h index f7038f4..05c23f5 100644 --- a/src/router.h +++ b/src/router.h @@ -88,15 +88,29 @@ struct router_vars { char *recvbuf; }; +struct rclient { + CRITICAL_SECTION cs; + BOOL cs_init; + + SOCKET sock; + + struct router_vars *router; + HANDLE thread; +}; + struct router_vars *router_init(BOOL global); 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, 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); +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_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); #endif /* !IPXWRAPPER_ROUTER_H */ diff --git a/src/winsock.c b/src/winsock.c index 6151388..545883f 100644 --- a/src/winsock.c +++ b/src/winsock.c @@ -148,7 +148,7 @@ int WSAAPI closesocket(SOCKET fd) { log_printf("IPX socket closed (fd = %d)", fd); - router_unbind(router, 0, fd); + rclient_unbind(&g_rclient, fd); if(ptr == sockets) { sockets = ptr->next; @@ -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), ptr->flags & IPX_REUSE ? TRUE : FALSE) == -1) { + if(!rclient_bind(&g_rclient, fd, &ipxaddr, &(ptr->nic_bcast), ptr->flags & IPX_REUSE ? TRUE : FALSE)) { RETURN(-1); } @@ -207,7 +207,7 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen) { if(r_bind(fd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) == -1) { log_printf("Binding local UDP socket failed: %s", w32_error(WSAGetLastError())); - router_unbind(router, 0, fd); + rclient_unbind(&g_rclient, fd); RETURN(-1); } @@ -216,14 +216,14 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen) { if(r_getsockname(fd, (struct sockaddr*)&bind_addr, &al) == -1) { log_printf("getsockname failed: %s", w32_error(WSAGetLastError())); - router_unbind(router, 0, fd); + rclient_unbind(&g_rclient, fd); RETURN(-1); } memcpy(&(ptr->addr), &ipxaddr, sizeof(ipxaddr)); ptr->flags |= IPX_BOUND; - router_set_port(router, 0, fd, bind_addr.sin_port); + rclient_set_port(&g_rclient, fd, bind_addr.sin_port); RETURN(0); }else{ @@ -503,18 +503,22 @@ int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval, } if(optname == IPX_FILTERPTYPE) { + if(!rclient_set_filter(&g_rclient, fd, *intval)) { + RETURN(-1); + } + sockptr->f_ptype = *intval; sockptr->flags |= IPX_FILTER; - router_set_filter(router, 0, fd, *intval); - RETURN(0); } if(optname == IPX_STOPFILTERPTYPE) { - sockptr->flags &= ~IPX_FILTER; + if(!rclient_set_filter(&g_rclient, fd, -1)) { + RETURN(-1); + } - router_set_filter(router, 0, fd, -1); + sockptr->flags &= ~IPX_FILTER; RETURN(0); } @@ -532,8 +536,7 @@ int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval, RETURN(0); }else if(optname == SO_REUSEADDR) { - if(!router_set_reuse(router, 0, fd, *bval)) { - WSASetLastError(WSAEINVAL); + if(!rclient_set_reuse(&g_rclient, fd, *bval)) { RETURN(-1); } @@ -635,13 +638,16 @@ int PASCAL shutdown(SOCKET fd, int cmd) { ipx_socket *sockptr = get_socket(fd); if(sockptr) { - if(cmd == SD_SEND || cmd == SD_BOTH) { - sockptr->flags &= ~IPX_SEND; + if(cmd == SD_RECEIVE || cmd == SD_BOTH) { + if(!rclient_set_port(&g_rclient, fd, 0)) { + RETURN(-1); + } + + sockptr->flags &= ~IPX_RECV; } - if(cmd == SD_RECEIVE || cmd == SD_BOTH) { - sockptr->flags &= ~IPX_RECV; - router_set_port(router, 0, fd, 0); + if(cmd == SD_SEND || cmd == SD_BOTH) { + sockptr->flags &= ~IPX_SEND; } RETURN(0);