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

Completed changes to allow for separate router processes.

This commit is contained in:
Daniel Collins 2011-09-09 18:36:52 +00:00
parent 11af1ba5d5
commit 8e06150325
6 changed files with 332 additions and 72 deletions

View File

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

View File

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

View File

@ -11,6 +11,7 @@ select
listen
accept
send
connect
WSACreateEvent
WSAEventSelect
WSACloseEvent

View File

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

View File

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

View File

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