2011-08-29 10:03:58 +00:00
|
|
|
/* IPXWrapper - Router code
|
|
|
|
* Copyright (C) 2011 Daniel Collins <solemnwarning@solemnwarning.net>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 as published by
|
|
|
|
* the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
* this program; if not, write to the Free Software Foundation, Inc., 51
|
|
|
|
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include <winsock2.h>
|
|
|
|
|
|
|
|
#include "router.h"
|
|
|
|
#include "common.h"
|
2011-08-29 10:57:19 +00:00
|
|
|
#include "ipxwrapper.h"
|
2011-08-29 13:41:10 +00:00
|
|
|
#include "interface.h"
|
2011-08-29 10:03:58 +00:00
|
|
|
|
2011-08-29 13:58:45 +00:00
|
|
|
static struct router_addr *router_get(struct router_vars *router, SOCKET control, SOCKET sock);
|
2011-09-09 17:38:57 +00:00
|
|
|
static void router_handle_call(struct router_vars *router, int coff);
|
|
|
|
static void router_drop_client(struct router_vars *router, int coff);
|
2011-08-29 13:58:45 +00:00
|
|
|
|
2011-08-29 10:03:58 +00:00
|
|
|
/* Allocate router_vars structure and initialise all members
|
|
|
|
* Returns NULL on failure
|
|
|
|
*/
|
|
|
|
struct router_vars *router_init(BOOL global) {
|
|
|
|
struct router_vars *router = malloc(sizeof(struct router_vars));
|
|
|
|
if(!router) {
|
|
|
|
log_printf("Not enough memory to create router_vars!");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
router->running = TRUE;
|
2011-08-29 10:57:19 +00:00
|
|
|
router->interfaces = NULL;
|
2011-08-29 10:03:58 +00:00
|
|
|
router->udp_sock = -1;
|
2011-09-09 15:50:55 +00:00
|
|
|
router->listener = -1;
|
|
|
|
router->client_count = 0;
|
2011-08-29 10:03:58 +00:00
|
|
|
router->wsa_event = WSA_INVALID_EVENT;
|
|
|
|
router->crit_sec_init = FALSE;
|
|
|
|
router->addrs = NULL;
|
2011-08-29 10:57:19 +00:00
|
|
|
router->recvbuf = NULL;
|
2011-08-29 10:03:58 +00:00
|
|
|
|
|
|
|
if(InitializeCriticalSectionAndSpinCount(&(router->crit_sec), 0x80000000)) {
|
|
|
|
router->crit_sec_init = TRUE;
|
|
|
|
}else{
|
|
|
|
log_printf("Error creating critical section: %s", w32_error(GetLastError()));
|
|
|
|
|
|
|
|
router_destroy(router);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((router->wsa_event = WSACreateEvent()) == WSA_INVALID_EVENT) {
|
|
|
|
log_printf("Error creating WSA event object: %s", w32_error(WSAGetLastError()));
|
|
|
|
|
|
|
|
router_destroy(router);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-08-29 10:57:19 +00:00
|
|
|
router->interfaces = get_interfaces(-1);
|
|
|
|
|
2011-08-29 10:03:58 +00:00
|
|
|
if((router->udp_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
|
|
|
|
log_printf("Error creating UDP socket: %s", w32_error(WSAGetLastError()));
|
|
|
|
|
|
|
|
router_destroy(router);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
|
|
|
addr.sin_family = AF_INET;
|
2011-09-07 20:03:16 +00:00
|
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
addr.sin_port = htons(global_conf.udp_port);
|
2011-08-29 10:03:58 +00:00
|
|
|
|
|
|
|
if(bind(router->udp_sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
|
2011-08-29 10:57:19 +00:00
|
|
|
log_printf("Error binding UDP socket: %s", w32_error(WSAGetLastError()));
|
|
|
|
|
|
|
|
router_destroy(router);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL broadcast = TRUE;
|
|
|
|
int bufsize = 524288; /* 512KiB */
|
|
|
|
|
|
|
|
setsockopt(router->udp_sock, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, sizeof(BOOL));
|
|
|
|
setsockopt(router->udp_sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufsize, sizeof(int));
|
|
|
|
setsockopt(router->udp_sock, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(int));
|
|
|
|
|
|
|
|
if(WSAEventSelect(router->udp_sock, router->wsa_event, FD_READ) == -1) {
|
|
|
|
log_printf("WSAEventSelect error: %s", w32_error(WSAGetLastError()));
|
|
|
|
|
|
|
|
router_destroy(router);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!(router->recvbuf = malloc(PACKET_BUF_SIZE))) {
|
|
|
|
log_printf("Out of memory! Cannot allocate recv buffer");
|
|
|
|
|
2011-08-29 10:03:58 +00:00
|
|
|
router_destroy(router);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(global) {
|
2011-09-09 15:50:55 +00:00
|
|
|
if((router->listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
|
|
|
log_printf("Failed to create TCP socket: %s", w32_error(WSAGetLastError()));
|
|
|
|
|
|
|
|
router_destroy(router);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: Use different port number for control socket? */
|
|
|
|
|
|
|
|
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
|
|
|
|
|
|
|
if(bind(router->listener, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
|
|
|
|
log_printf("Failed to bind TCP socket: %s", w32_error(WSAGetLastError()));
|
|
|
|
|
|
|
|
router_destroy(router);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(listen(router->listener, 8) == -1) {
|
|
|
|
log_printf("Failed to listen for connections: %s", w32_error(WSAGetLastError()));
|
|
|
|
|
|
|
|
router_destroy(router);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(WSAEventSelect(router->listener, router->wsa_event, FD_ACCEPT) == -1) {
|
|
|
|
log_printf("WSAEventSelect error: %s", w32_error(WSAGetLastError()));
|
|
|
|
|
|
|
|
router_destroy(router);
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-08-29 10:03:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return router;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Release all resources allocated by a router and free it */
|
|
|
|
void router_destroy(struct router_vars *router) {
|
2011-08-29 10:57:19 +00:00
|
|
|
struct router_addr *addr = router->addrs;
|
2011-09-09 15:50:55 +00:00
|
|
|
int i;
|
2011-08-29 10:57:19 +00:00
|
|
|
|
|
|
|
while(addr) {
|
|
|
|
struct router_addr *del = addr;
|
|
|
|
addr = addr->next;
|
|
|
|
|
|
|
|
free(del);
|
|
|
|
}
|
|
|
|
|
2011-09-09 15:50:55 +00:00
|
|
|
for(i = 0; i < router->client_count; i++) {
|
|
|
|
closesocket(router->clients[i].sock);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(router->listener != -1) {
|
|
|
|
closesocket(router->listener);
|
|
|
|
}
|
|
|
|
|
2011-08-29 10:57:19 +00:00
|
|
|
free(router->recvbuf);
|
|
|
|
|
2011-08-29 10:03:58 +00:00
|
|
|
if(router->udp_sock != -1) {
|
|
|
|
closesocket(router->udp_sock);
|
|
|
|
}
|
|
|
|
|
2011-08-29 10:57:19 +00:00
|
|
|
free_interfaces(router->interfaces);
|
|
|
|
|
2011-08-29 10:03:58 +00:00
|
|
|
if(router->wsa_event != WSA_INVALID_EVENT) {
|
|
|
|
WSACloseEvent(router->wsa_event);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(router->crit_sec_init) {
|
|
|
|
DeleteCriticalSection(&(router->crit_sec));
|
|
|
|
}
|
|
|
|
|
|
|
|
free(router);
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD router_main(void *arg) {
|
|
|
|
struct router_vars *router = arg;
|
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
const unsigned char f6[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
|
|
|
|
|
2011-08-29 10:03:58 +00:00
|
|
|
while(1) {
|
|
|
|
WaitForSingleObject(router->wsa_event, INFINITE);
|
|
|
|
|
|
|
|
EnterCriticalSection(&(router->crit_sec));
|
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
WSAResetEvent(router->wsa_event);
|
|
|
|
|
2011-08-29 10:03:58 +00:00
|
|
|
if(!router->running) {
|
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
|
|
|
|
2011-09-09 15:50:55 +00:00
|
|
|
if(router->listener != -1) {
|
|
|
|
int newfd = accept(router->listener, NULL, NULL);
|
|
|
|
if(newfd != -1) {
|
|
|
|
if(router->client_count == MAX_ROUTER_CLIENTS) {
|
|
|
|
log_printf("Too many clients, dropping new connection!");
|
|
|
|
goto DROP_NEWFD;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(WSAEventSelect(newfd, router->wsa_event, FD_READ | FD_CLOSE) == -1) {
|
|
|
|
log_printf("WSAEventSelect error: %s", w32_error(WSAGetLastError()));
|
|
|
|
goto DROP_NEWFD;
|
|
|
|
}
|
|
|
|
|
|
|
|
router->clients[router->client_count].sock = newfd;
|
|
|
|
router->clients[router->client_count++].recvbuf_len = 0;
|
|
|
|
|
|
|
|
if(0) {
|
|
|
|
DROP_NEWFD:
|
|
|
|
closesocket(newfd);
|
|
|
|
}
|
|
|
|
}else if(WSAGetLastError() != WSAEWOULDBLOCK) {
|
|
|
|
log_printf("Failed to accept client connection: %s", w32_error(WSAGetLastError()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < router->client_count; i++) {
|
|
|
|
char *bstart = ((char*)&(router->clients[i].recvbuf)) + router->clients[i].recvbuf_len;
|
|
|
|
int len = sizeof(struct router_call) - router->clients[i].recvbuf_len;
|
|
|
|
|
|
|
|
if((len = recv(router->clients[i].sock, bstart, len, 0) == -1) || len == 0) {
|
2011-09-09 17:38:57 +00:00
|
|
|
if(WSAGetLastError() == WSAEWOULDBLOCK) {
|
2011-09-09 15:50:55 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(len == -1) {
|
|
|
|
log_printf("Error reading from client socket: %s", w32_error(WSAGetLastError()));
|
|
|
|
}
|
|
|
|
|
2011-09-09 17:38:57 +00:00
|
|
|
router_drop_client(router, i);
|
2011-09-09 15:50:55 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((router->clients[i].recvbuf_len += len) == sizeof(struct router_call)) {
|
2011-09-09 17:38:57 +00:00
|
|
|
router_handle_call(router, i);
|
2011-09-09 15:50:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-29 10:57:19 +00:00
|
|
|
struct sockaddr_in addr;
|
|
|
|
int addrlen = sizeof(addr);
|
|
|
|
|
2011-09-08 23:28:36 +00:00
|
|
|
int len = recvfrom(router->udp_sock, router->recvbuf, PACKET_BUF_SIZE, 0, (struct sockaddr*)&addr, &addrlen);
|
2011-08-29 10:57:19 +00:00
|
|
|
if(len == -1) {
|
2011-09-07 20:03:16 +00:00
|
|
|
if(WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAECONNRESET) {
|
2011-08-29 10:57:19 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_printf("Error reading from UDP socket: %s", w32_error(WSAGetLastError()));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
EnterCriticalSection(&(router->crit_sec));
|
|
|
|
|
2011-08-29 13:41:10 +00:00
|
|
|
ipx_packet *packet = (ipx_packet*)router->recvbuf;
|
|
|
|
|
|
|
|
/* Check that the packet arrived from the subnet of an enabled network
|
|
|
|
* interface and drop it if not.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if(global_conf.filter) {
|
|
|
|
struct ipx_interface *iface = router->interfaces;
|
|
|
|
|
|
|
|
while(iface) {
|
|
|
|
if((iface->ipaddr & iface->netmask) == (addr.sin_addr.s_addr & iface->netmask)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface = iface->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!iface) {
|
2011-09-07 20:03:16 +00:00
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
2011-08-29 13:41:10 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
packet->size = ntohs(packet->size);
|
|
|
|
|
|
|
|
if(packet->size > MAX_PACKET_SIZE || packet->size + sizeof(ipx_packet) - 1 != len) {
|
2011-09-07 20:03:16 +00:00
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
2011-08-29 13:41:10 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-09-07 20:37:18 +00:00
|
|
|
/* Replace destination network field of packet with source IP address
|
|
|
|
* so that the client can cache it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
char dest_net[4];
|
|
|
|
|
|
|
|
memcpy(dest_net, packet->dest_net, 4);
|
|
|
|
memcpy(packet->dest_net, &(addr.sin_addr.s_addr), 4);
|
2011-08-29 13:41:10 +00:00
|
|
|
|
|
|
|
struct router_addr *ra = router->addrs;
|
|
|
|
|
|
|
|
while(ra) {
|
|
|
|
if(
|
2011-08-29 13:58:45 +00:00
|
|
|
ra->local_port &&
|
|
|
|
(ra->filter_ptype < 0 || ra->filter_ptype == packet->ptype) &&
|
2011-09-07 20:37:18 +00:00
|
|
|
(memcmp(dest_net, ra->addr.sa_netnum, 4) == 0 || memcmp(dest_net, f6, 4) == 0) &&
|
2011-08-29 13:41:10 +00:00
|
|
|
(memcmp(packet->dest_node, ra->addr.sa_nodenum, 6) == 0 || memcmp(packet->dest_node, f6, 6) == 0) &&
|
|
|
|
packet->dest_socket == ra->addr.sa_socket
|
|
|
|
) {
|
|
|
|
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
2011-08-29 13:58:45 +00:00
|
|
|
addr.sin_port = ra->local_port;
|
2011-08-29 13:41:10 +00:00
|
|
|
|
2011-09-08 23:28:36 +00:00
|
|
|
if(sendto(router->udp_sock, (char*)packet, len, 0, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
|
2011-08-29 13:41:10 +00:00
|
|
|
log_printf("Error relaying packet: %s", w32_error(WSAGetLastError()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ra = ra->next;
|
|
|
|
}
|
2011-08-29 10:03:58 +00:00
|
|
|
|
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-08 18:28:01 +00:00
|
|
|
int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast, BOOL reuse) {
|
2011-09-07 20:03:16 +00:00
|
|
|
/* 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.
|
|
|
|
*
|
|
|
|
* According to MSDN 6, IPX socket numbers are unique to systems rather than
|
|
|
|
* interfaces and as such, the same socket number cannot be bound to more than
|
|
|
|
* one interface, my code lacks any "catch all" address like INADDR_ANY as I have
|
|
|
|
* not found any mentions of an equivalent address for IPX. This means that a
|
|
|
|
* given socket number may only be used on one interface.
|
|
|
|
*
|
|
|
|
* If you know the above information about IPX socket numbers to be incorrect,
|
|
|
|
* PLEASE email me with corrections!
|
|
|
|
*/
|
|
|
|
|
2011-08-29 10:03:58 +00:00
|
|
|
struct ipx_interface *ifaces = get_interfaces(-1), *iface;
|
|
|
|
unsigned char z6[] = {0,0,0,0,0,0};
|
|
|
|
|
|
|
|
for(iface = ifaces; iface; iface = iface->next) {
|
|
|
|
if(
|
|
|
|
(memcmp(addr->sa_netnum, iface->ipx_net, 4) == 0 || memcmp(addr->sa_netnum, z6, 4) == 0) &&
|
|
|
|
(memcmp(addr->sa_nodenum, iface->ipx_node, 6) == 0 || memcmp(addr->sa_nodenum, z6, 6) == 0)
|
|
|
|
) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!iface) {
|
|
|
|
log_printf("bind failed: no such address");
|
|
|
|
|
|
|
|
free_interfaces(ifaces);
|
|
|
|
|
|
|
|
WSASetLastError(WSAEADDRNOTAVAIL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(addr->sa_netnum, iface->ipx_net, 4);
|
|
|
|
memcpy(addr->sa_nodenum, iface->ipx_node, 6);
|
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
*nic_bcast = iface->bcast;
|
|
|
|
|
2011-08-29 10:03:58 +00:00
|
|
|
free_interfaces(ifaces);
|
|
|
|
|
|
|
|
EnterCriticalSection(&(router->crit_sec));
|
|
|
|
|
2011-08-29 13:58:45 +00:00
|
|
|
if(router_get(router, control, sock)) {
|
|
|
|
log_printf("bind failed: socket already bound");
|
|
|
|
|
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
2011-08-29 10:57:19 +00:00
|
|
|
|
2011-08-29 13:58:45 +00:00
|
|
|
WSASetLastError(WSAEINVAL);
|
|
|
|
return -1;
|
2011-08-29 10:57:19 +00:00
|
|
|
}
|
|
|
|
|
2011-08-29 10:03:58 +00:00
|
|
|
if(addr->sa_socket == 0) {
|
|
|
|
/* Automatic socket allocations start at 1024, I have no idea if
|
|
|
|
* this is normal IPX behaviour, but IP does it and it doesn't seem
|
|
|
|
* to interfere with any IPX software I've tested.
|
|
|
|
*/
|
|
|
|
|
|
|
|
uint16_t s = 1024;
|
2011-08-29 13:58:45 +00:00
|
|
|
struct router_addr *a = router->addrs;
|
2011-08-29 10:03:58 +00:00
|
|
|
|
|
|
|
while(a) {
|
|
|
|
if(ntohs(a->addr.sa_socket) == s) {
|
|
|
|
if(s == 65535) {
|
|
|
|
log_printf("bind failed: out of sockets?!");
|
|
|
|
|
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
|
|
|
|
|
|
|
WSASetLastError(WSAEADDRNOTAVAIL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
s++;
|
|
|
|
a = router->addrs;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
a = a->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr->sa_socket = htons(s);
|
2011-09-08 18:28:01 +00:00
|
|
|
}else{
|
2011-08-29 10:03:58 +00:00
|
|
|
/* Test if any bound socket is using the requested socket number. */
|
|
|
|
|
2011-08-29 13:58:45 +00:00
|
|
|
struct router_addr *a = router->addrs;
|
2011-08-29 10:03:58 +00:00
|
|
|
|
|
|
|
while(a) {
|
2011-09-08 18:28:01 +00:00
|
|
|
if(a->addr.sa_socket == addr->sa_socket && (!a->reuse || !reuse)) {
|
2011-08-29 10:03:58 +00:00
|
|
|
log_printf("bind failed: requested socket in use");
|
|
|
|
|
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
|
|
|
|
|
|
|
WSASetLastError(WSAEADDRINUSE);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
a = a->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct router_addr *new_addr = malloc(sizeof(struct router_addr));
|
|
|
|
if(!new_addr) {
|
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
|
|
|
|
|
|
|
WSASetLastError(ERROR_OUTOFMEMORY);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&(new_addr->addr), addr, sizeof(struct sockaddr_ipx));
|
|
|
|
|
|
|
|
new_addr->local_port = 0;
|
|
|
|
new_addr->ws_socket = sock;
|
|
|
|
new_addr->control_socket = control;
|
2011-08-29 13:58:45 +00:00
|
|
|
new_addr->filter_ptype = -1;
|
2011-09-08 18:28:01 +00:00
|
|
|
new_addr->reuse = reuse;
|
2011-08-29 10:03:58 +00:00
|
|
|
new_addr->next = NULL;
|
|
|
|
|
|
|
|
router->addrs = new_addr;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2011-08-29 10:57:19 +00:00
|
|
|
|
2011-08-29 13:58:45 +00:00
|
|
|
/* Set loopback UDP port of emulation socket in NETWORK BYTE ORDER
|
|
|
|
* Disable recv by setting to zero
|
|
|
|
*/
|
2011-08-29 10:57:19 +00:00
|
|
|
void router_set_port(struct router_vars *router, SOCKET control, SOCKET sock, uint16_t port) {
|
|
|
|
EnterCriticalSection(&(router->crit_sec));
|
|
|
|
|
2011-08-29 13:58:45 +00:00
|
|
|
struct router_addr *addr = router_get(router, control, sock);
|
|
|
|
if(addr) {
|
|
|
|
addr->local_port = port;
|
2011-08-29 10:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
|
|
|
}
|
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
void router_unbind(struct router_vars *router, SOCKET control, SOCKET sock) {
|
2011-08-29 10:57:19 +00:00
|
|
|
EnterCriticalSection(&(router->crit_sec));
|
|
|
|
|
|
|
|
struct router_addr *addr = router->addrs, *prev = NULL;
|
|
|
|
|
|
|
|
while(addr) {
|
|
|
|
if(addr->control_socket == control && addr->ws_socket == sock) {
|
|
|
|
if(prev) {
|
|
|
|
prev->next = addr->next;
|
|
|
|
}else{
|
|
|
|
router->addrs = addr->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(addr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
prev = addr;
|
|
|
|
addr = addr->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
|
|
|
}
|
2011-08-29 13:58:45 +00:00
|
|
|
|
|
|
|
/* Return the address a given socket is bound to, NULL if unbound */
|
|
|
|
static struct router_addr *router_get(struct router_vars *router, SOCKET control, SOCKET sock) {
|
|
|
|
EnterCriticalSection(&(router->crit_sec));
|
|
|
|
|
|
|
|
struct router_addr *addr = router->addrs;
|
|
|
|
|
|
|
|
while(addr && (addr->control_socket != control || addr->ws_socket != sock)) {
|
|
|
|
addr = addr->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
|
|
|
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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) {
|
|
|
|
EnterCriticalSection(&(router->crit_sec));
|
|
|
|
|
|
|
|
struct router_addr *addr = router_get(router, control, sock);
|
|
|
|
if(addr) {
|
|
|
|
addr->filter_ptype = ptype;
|
|
|
|
}
|
|
|
|
|
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
|
|
|
}
|
2011-09-08 18:28:01 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2011-09-09 17:38:57 +00:00
|
|
|
|
|
|
|
static void router_handle_call(struct router_vars *router, int coff) {
|
|
|
|
struct router_call call = router->clients[coff].recvbuf;
|
|
|
|
struct router_ret ret;
|
|
|
|
|
|
|
|
ret.err_code = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
switch(call.call) {
|
|
|
|
case rc_bind: {
|
|
|
|
ret.ret_addr = call.arg_addr;
|
|
|
|
|
|
|
|
if(router_bind(router, router->clients[coff].sock, call.sock, &(ret.ret_addr), &(ret.ret_u32), call.arg_int) == -1) {
|
|
|
|
ret.err_code = WSAGetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case rc_unbind: {
|
|
|
|
router_unbind(router, router->clients[coff].sock, call.sock);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case rc_port: {
|
|
|
|
router_set_port(router, router->clients[coff].sock, call.sock, call.arg_int);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case rc_filter: {
|
|
|
|
router_set_filter(router, router->clients[coff].sock, call.sock, call.arg_int);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case rc_reuse: {
|
|
|
|
if(!router_set_reuse(router, router->clients[coff].sock, call.sock, call.arg_int)) {
|
|
|
|
ret.err_code = WSAEINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default: {
|
|
|
|
log_printf("Recieved unknown call, dropping client");
|
|
|
|
|
|
|
|
router_drop_client(router, coff);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int sent = 0, sr;
|
|
|
|
|
|
|
|
while(sent < sizeof(ret)) {
|
|
|
|
char *sbuf = ((char*)&ret) + sent;
|
|
|
|
|
|
|
|
if((sr = send(router->clients[coff].sock, sbuf, sizeof(ret) - sent, 0)) == -1) {
|
|
|
|
log_printf("Send error: %s, dropping client", w32_error(WSAGetLastError()));
|
|
|
|
|
|
|
|
router_drop_client(router, coff);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sent += sr;
|
|
|
|
}
|
|
|
|
|
|
|
|
router->clients[coff].recvbuf_len = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void router_drop_client(struct router_vars *router, int coff) {
|
|
|
|
EnterCriticalSection(&(router->crit_sec));
|
|
|
|
|
|
|
|
struct router_addr *addr = router->addrs, *dp = NULL;
|
|
|
|
|
|
|
|
while(addr) {
|
|
|
|
dp = addr->control_socket == router->clients[coff].sock ? addr : NULL;
|
|
|
|
addr = addr->next;
|
|
|
|
|
|
|
|
if(dp) {
|
|
|
|
router_unbind(router, dp->control_socket, dp->ws_socket);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LeaveCriticalSection(&(router->crit_sec));
|
|
|
|
|
|
|
|
closesocket(router->clients[coff].sock);
|
|
|
|
router->clients[coff] = router->clients[--router->client_count];
|
|
|
|
}
|