mirror of
https://github.com/solemnwarning/ipxwrapper
synced 2024-12-30 16:45:37 +01:00
Switchover to new router code
This commit is contained in:
parent
37e9db8fba
commit
d046b6522d
4
Makefile
4
Makefile
@ -18,14 +18,14 @@ CFLAGS := -Wall -I./include/
|
||||
CXXFLAGS := -Wall -I./include/
|
||||
|
||||
IPXWRAPPER_DEPS := src/ipxwrapper.o src/winsock.o src/ipxwrapper_stubs.o src/log.o src/common.o \
|
||||
src/interface.o src/ipxwrapper.def
|
||||
src/interface.o src/router.o src/ipxwrapper.def
|
||||
|
||||
BIN_FILES := changes.txt license.txt readme.txt ipxwrapper.dll mswsock.dll wsock32.dll ipxconfig.exe
|
||||
SRC_FILES := changes.txt license.txt Makefile mkstubs.pl readme.txt src/config.h src/ipxconfig.cpp \
|
||||
src/ipxwrapper.c src/ipxwrapper.def src/ipxwrapper.h src/ipxwrapper_stubs.txt src/log.c \
|
||||
src/mswsock.def src/mswsock_stubs.txt src/stubdll.c src/winsock.c src/winstuff.h src/wsock32.def \
|
||||
src/wsock32_stubs.txt src/directplay.c src/dpwsockx.def src/dpwsockx_stubs.txt src/common.c \
|
||||
src/common.h include/dplay.h include/dplaysp.h include/dplobby.h
|
||||
src/common.h src/router.c src/router.h include/dplay.h include/dplaysp.h include/dplobby.h
|
||||
|
||||
all: ipxwrapper.dll wsock32.dll mswsock.dll ipxconfig.exe dpwsockx.dll
|
||||
|
||||
|
174
src/ipxwrapper.c
174
src/ipxwrapper.c
@ -29,6 +29,7 @@
|
||||
#include "ipxwrapper.h"
|
||||
#include "common.h"
|
||||
#include "interface.h"
|
||||
#include "router.h"
|
||||
|
||||
#define DLL_UNLOAD(dll) \
|
||||
if(dll) {\
|
||||
@ -41,7 +42,6 @@ struct ipx_interface *nics = NULL;
|
||||
ipx_host *hosts = NULL;
|
||||
SOCKET net_fd = -1;
|
||||
struct reg_global global_conf;
|
||||
static void *router_buf = NULL;
|
||||
|
||||
HMODULE winsock2_dll = NULL;
|
||||
HMODULE mswsock_dll = NULL;
|
||||
@ -49,10 +49,9 @@ HMODULE wsock32_dll = NULL;
|
||||
|
||||
static HANDLE mutex = NULL;
|
||||
static HANDLE router_thread = NULL;
|
||||
static DWORD router_tid = 0;
|
||||
struct router_vars *router = NULL;
|
||||
|
||||
static int init_router(void);
|
||||
static DWORD WINAPI router_main(LPVOID argp);
|
||||
static BOOL start_router(void);
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res) {
|
||||
if(why == DLL_PROCESS_ATTACH) {
|
||||
@ -90,21 +89,23 @@ BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!init_router()) {
|
||||
if(!start_router()) {
|
||||
return FALSE;
|
||||
}
|
||||
}else if(why == DLL_PROCESS_DETACH) {
|
||||
if(router_thread && GetCurrentThreadId() != router_tid) {
|
||||
TerminateThread(router_thread, 0);
|
||||
if(router_thread) {
|
||||
EnterCriticalSection(&(router->crit_sec));
|
||||
|
||||
router->running = FALSE;
|
||||
SetEvent(router->wsa_event);
|
||||
|
||||
LeaveCriticalSection(&(router->crit_sec));
|
||||
|
||||
WaitForSingleObject(router_thread, INFINITE);
|
||||
router_thread = NULL;
|
||||
}
|
||||
|
||||
free(router_buf);
|
||||
router_buf = NULL;
|
||||
|
||||
if(net_fd >= 0) {
|
||||
closesocket(net_fd);
|
||||
net_fd = -1;
|
||||
|
||||
router_destroy(router);
|
||||
router = NULL;
|
||||
}
|
||||
|
||||
if(mutex) {
|
||||
@ -182,143 +183,24 @@ void unlock_mutex(void) {
|
||||
}
|
||||
|
||||
/* Initialize and start the router thread */
|
||||
static int init_router(void) {
|
||||
net_fd = r_socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(net_fd == -1) {
|
||||
log_printf("Failed to create network socket: %s", w32_error(WSAGetLastError()));
|
||||
return 0;
|
||||
static BOOL start_router(void) {
|
||||
if(!(router = router_init(FALSE))) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct sockaddr_in bind_addr;
|
||||
bind_addr.sin_family = AF_INET;
|
||||
bind_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
bind_addr.sin_port = htons(global_conf.udp_port);
|
||||
|
||||
if(r_bind(net_fd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) == -1) {
|
||||
log_printf("Failed to bind network socket: %s", w32_error(WSAGetLastError()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL broadcast = TRUE;
|
||||
int bufsize = 524288; /* 512KiB */
|
||||
|
||||
r_setsockopt(net_fd, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, sizeof(BOOL));
|
||||
r_setsockopt(net_fd, SOL_SOCKET, SO_RCVBUF, (char*)&bufsize, sizeof(int));
|
||||
r_setsockopt(net_fd, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(int));
|
||||
|
||||
router_buf = malloc(PACKET_BUF_SIZE);
|
||||
if(!router_buf) {
|
||||
log_printf("Not enough memory for router buffer (64KiB)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
router_thread = CreateThread(NULL, 0, &router_main, NULL, 0, &router_tid);
|
||||
router_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&router_main, router, 0, NULL);
|
||||
if(!router_thread) {
|
||||
log_printf("Failed to create router thread");
|
||||
return 0;
|
||||
log_printf("Failed to create router thread: %s", w32_error(GetLastError()));
|
||||
|
||||
router_destroy(router);
|
||||
router = NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Router thread main function
|
||||
*
|
||||
* The router thread recieves packets from the listening port and forwards them
|
||||
* to the UDP sockets which emulate IPX.
|
||||
*/
|
||||
static DWORD WINAPI router_main(LPVOID notused) {
|
||||
ipx_packet *packet = router_buf;
|
||||
int addrlen, rval, sval;
|
||||
unsigned char f6[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
|
||||
struct sockaddr_in addr;
|
||||
ipx_socket *sockptr;
|
||||
net_fd = router->udp_sock;
|
||||
|
||||
while(1) {
|
||||
addrlen = sizeof(addr);
|
||||
rval = r_recvfrom(net_fd, (char*)packet, PACKET_BUF_SIZE, 0, (struct sockaddr*)&addr, &addrlen);
|
||||
if(rval <= 0) {
|
||||
log_printf("Error recieving packet: %s", w32_error(WSAGetLastError()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if(global_conf.filter) {
|
||||
struct ipx_interface *nic = nics;
|
||||
|
||||
while(nic) {
|
||||
if((nic->ipaddr & nic->netmask) == (addr.sin_addr.s_addr & nic->netmask)) {
|
||||
break;
|
||||
}
|
||||
|
||||
nic = nic->next;
|
||||
}
|
||||
|
||||
if(!nic) {
|
||||
/* Packet not recieved from subnet of an enabled interface */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
packet->size = ntohs(packet->size);
|
||||
|
||||
if(packet->size > MAX_PACKET_SIZE || packet->size+sizeof(ipx_packet)-1 != rval) {
|
||||
log_printf("Recieved packet with incorrect size field, discarding");
|
||||
continue;
|
||||
}
|
||||
|
||||
lock_mutex();
|
||||
|
||||
add_host(packet->src_net, packet->src_node, addr.sin_addr.s_addr);
|
||||
|
||||
for(sockptr = sockets; sockptr; sockptr = sockptr->next) {
|
||||
if(
|
||||
sockptr->flags & IPX_RECV &&
|
||||
(
|
||||
!(sockptr->flags & IPX_FILTER) ||
|
||||
packet->ptype == sockptr->f_ptype
|
||||
) && ((
|
||||
sockptr->flags & IPX_BOUND &&
|
||||
packet->dest_socket == sockptr->socket &&
|
||||
(
|
||||
memcmp(packet->dest_net, sockptr->nic->ipx_net, 4) == 0 ||
|
||||
(
|
||||
memcmp(packet->dest_net, f6, 4) == 0 &&
|
||||
(!global_conf.w95_bug || sockptr->flags & IPX_BROADCAST)
|
||||
)
|
||||
) && (
|
||||
memcmp(packet->dest_node, sockptr->nic->ipx_node, 6) == 0 ||
|
||||
(
|
||||
memcmp(packet->dest_node, f6, 6) == 0 &&
|
||||
(!global_conf.w95_bug || sockptr->flags & IPX_BROADCAST)
|
||||
)
|
||||
)
|
||||
) || (
|
||||
sockptr->flags & IPX_EX_BOUND &&
|
||||
packet->dest_socket == sockptr->ex_socket &&
|
||||
(
|
||||
memcmp(packet->dest_net, sockptr->ex_nic->ipx_net, 4) == 0 ||
|
||||
memcmp(packet->dest_net, f6, 4) == 0
|
||||
) && (
|
||||
memcmp(packet->dest_node, sockptr->ex_nic->ipx_node, 6) == 0 ||
|
||||
memcmp(packet->dest_node, f6, 6) == 0
|
||||
)
|
||||
))
|
||||
) {
|
||||
addrlen = sizeof(addr);
|
||||
if(r_getsockname(sockptr->fd, (struct sockaddr*)&addr, &addrlen) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sval = r_sendto(sockptr->fd, (char*)packet, rval, 0, (struct sockaddr*)&addr, addrlen);
|
||||
if(sval == -1) {
|
||||
log_printf("Error relaying packet: %s", w32_error(WSAGetLastError()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unlock_mutex();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Add a host to the hosts list or update an existing one */
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "router.h"
|
||||
|
||||
/* Maximum UDP data size is 65467, we use a smaller value to ensure we have
|
||||
* plenty of space to play with for headers, etc
|
||||
@ -65,8 +66,8 @@ struct ipx_socket {
|
||||
uint8_t f_ptype; /* Undefined when IPX_FILTER isn't set */
|
||||
|
||||
/* The following values are undefined when IPX_BOUND is not set */
|
||||
struct ipx_interface *nic;
|
||||
uint16_t socket; /* Stored in NETWORK BYTE ORDER */
|
||||
struct sockaddr_ipx addr;
|
||||
uint32_t nic_bcast;
|
||||
|
||||
/* Extra bind address, only used for receiving packets.
|
||||
* Only defined when IPX_EX_BOUND is set.
|
||||
@ -107,6 +108,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 HMODULE winsock2_dll;
|
||||
extern HMODULE mswsock_dll;
|
||||
|
@ -8,6 +8,10 @@ ntohl
|
||||
htons
|
||||
ntohs
|
||||
select
|
||||
WSACreateEvent
|
||||
WSAEventSelect
|
||||
WSACloseEvent
|
||||
WSAResetEvent
|
||||
r_EnumProtocolsA
|
||||
r_EnumProtocolsW
|
||||
r_WSARecvEx
|
||||
|
44
src/router.c
44
src/router.c
@ -72,8 +72,8 @@ struct router_vars *router_init(BOOL global) {
|
||||
struct sockaddr_in addr;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
addr.sin_port = 9999;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_port = htons(global_conf.udp_port);
|
||||
|
||||
if(bind(router->udp_sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
|
||||
log_printf("Error binding UDP socket: %s", w32_error(WSAGetLastError()));
|
||||
@ -143,24 +143,28 @@ void router_destroy(struct router_vars *router) {
|
||||
DWORD router_main(void *arg) {
|
||||
struct router_vars *router = arg;
|
||||
|
||||
const unsigned char f6[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
|
||||
|
||||
while(1) {
|
||||
WaitForSingleObject(router->wsa_event, INFINITE);
|
||||
|
||||
EnterCriticalSection(&(router->crit_sec));
|
||||
|
||||
WSAResetEvent(router->wsa_event);
|
||||
|
||||
if(!router->running) {
|
||||
LeaveCriticalSection(&(router->crit_sec));
|
||||
return 0;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&(router->crit_sec));
|
||||
|
||||
struct sockaddr_in addr;
|
||||
int addrlen = sizeof(addr);
|
||||
|
||||
int len = recvfrom(router->udp_sock, router->recvbuf, PACKET_BUF_SIZE, 0, (struct sockaddr*)&addr, &addrlen);
|
||||
int len = r_recvfrom(router->udp_sock, router->recvbuf, PACKET_BUF_SIZE, 0, (struct sockaddr*)&addr, &addrlen);
|
||||
if(len == -1) {
|
||||
LeaveCriticalSection(&(router->crit_sec));
|
||||
|
||||
if(WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||
if(WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAECONNRESET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -168,6 +172,8 @@ DWORD router_main(void *arg) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&(router->crit_sec));
|
||||
|
||||
ipx_packet *packet = (ipx_packet*)router->recvbuf;
|
||||
|
||||
/* Check that the packet arrived from the subnet of an enabled network
|
||||
@ -186,6 +192,7 @@ DWORD router_main(void *arg) {
|
||||
}
|
||||
|
||||
if(!iface) {
|
||||
LeaveCriticalSection(&(router->crit_sec));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -193,7 +200,7 @@ DWORD router_main(void *arg) {
|
||||
packet->size = ntohs(packet->size);
|
||||
|
||||
if(packet->size > MAX_PACKET_SIZE || packet->size + sizeof(ipx_packet) - 1 != len) {
|
||||
log_printf("Recieved packet with incorrect size field, discarding");
|
||||
LeaveCriticalSection(&(router->crit_sec));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -202,8 +209,6 @@ DWORD router_main(void *arg) {
|
||||
struct router_addr *ra = router->addrs;
|
||||
|
||||
while(ra) {
|
||||
unsigned char f6[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
|
||||
|
||||
if(
|
||||
ra->local_port &&
|
||||
(ra->filter_ptype < 0 || ra->filter_ptype == packet->ptype) &&
|
||||
@ -214,7 +219,7 @@ DWORD router_main(void *arg) {
|
||||
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
addr.sin_port = ra->local_port;
|
||||
|
||||
if(sendto(router->udp_sock, (char*)packet, len, 0, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
|
||||
if(r_sendto(router->udp_sock, (char*)packet, len, 0, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
|
||||
log_printf("Error relaying packet: %s", w32_error(WSAGetLastError()));
|
||||
}
|
||||
}
|
||||
@ -228,7 +233,20 @@ DWORD router_main(void *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr) {
|
||||
int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast) {
|
||||
/* 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!
|
||||
*/
|
||||
|
||||
struct ipx_interface *ifaces = get_interfaces(-1), *iface;
|
||||
unsigned char z6[] = {0,0,0,0,0,0};
|
||||
|
||||
@ -253,6 +271,8 @@ int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct
|
||||
memcpy(addr->sa_netnum, iface->ipx_net, 4);
|
||||
memcpy(addr->sa_nodenum, iface->ipx_node, 6);
|
||||
|
||||
*nic_bcast = iface->bcast;
|
||||
|
||||
free_interfaces(ifaces);
|
||||
|
||||
EnterCriticalSection(&(router->crit_sec));
|
||||
@ -352,7 +372,7 @@ void router_set_port(struct router_vars *router, SOCKET control, SOCKET sock, ui
|
||||
LeaveCriticalSection(&(router->crit_sec));
|
||||
}
|
||||
|
||||
void router_close(struct router_vars *router, SOCKET control, SOCKET sock) {
|
||||
void router_unbind(struct router_vars *router, SOCKET control, SOCKET sock) {
|
||||
EnterCriticalSection(&(router->crit_sec));
|
||||
|
||||
struct router_addr *addr = router->addrs, *prev = NULL;
|
||||
|
@ -61,9 +61,11 @@ struct router_vars {
|
||||
struct router_vars *router_init(BOOL global);
|
||||
void router_destroy(struct router_vars *router);
|
||||
|
||||
int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr);
|
||||
DWORD router_main(void *arg);
|
||||
|
||||
int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast);
|
||||
void router_set_port(struct router_vars *router, SOCKET control, SOCKET sock, uint16_t port);
|
||||
void router_close(struct router_vars *router, SOCKET control, SOCKET sock);
|
||||
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);
|
||||
|
||||
#endif /* !IPXWRAPPER_ROUTER_H */
|
||||
|
211
src/winsock.c
211
src/winsock.c
@ -26,6 +26,7 @@
|
||||
#include "ipxwrapper.h"
|
||||
#include "common.h"
|
||||
#include "interface.h"
|
||||
#include "router.h"
|
||||
|
||||
INT APIENTRY EnumProtocolsA(LPINT protocols, LPVOID buf, LPDWORD bsptr) {
|
||||
int bufsize = *bsptr, rval, i, want_ipx = 0;
|
||||
@ -180,6 +181,8 @@ int WSAAPI closesocket(SOCKET fd) {
|
||||
|
||||
log_printf("IPX socket closed (fd = %d)", fd);
|
||||
|
||||
router_unbind(router, 0, fd);
|
||||
|
||||
if(ptr == sockets) {
|
||||
sockets = ptr->next;
|
||||
free(ptr);
|
||||
@ -201,122 +204,61 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen) {
|
||||
ipx_socket *ptr = get_socket(fd);
|
||||
|
||||
if(ptr) {
|
||||
struct sockaddr_ipx *ipxaddr = (struct sockaddr_ipx*)addr;
|
||||
struct sockaddr_ipx ipxaddr;
|
||||
char net_s[12], node_s[18];
|
||||
|
||||
NET_TO_STRING(net_s, ipxaddr->sa_netnum);
|
||||
NODE_TO_STRING(node_s, ipxaddr->sa_nodenum);
|
||||
if(addrlen < sizeof(ipxaddr)) {
|
||||
RETURN_WSA(WSAEFAULT, -1);
|
||||
}
|
||||
|
||||
log_printf("bind(%d, net=%s node=%s socket=%hu)", fd, net_s, node_s, ntohs(ipxaddr->sa_socket));
|
||||
memcpy(&ipxaddr, addr, sizeof(ipxaddr));
|
||||
|
||||
NET_TO_STRING(net_s, ipxaddr.sa_netnum);
|
||||
NODE_TO_STRING(node_s, ipxaddr.sa_nodenum);
|
||||
|
||||
log_printf("bind(%d, net=%s node=%s socket=%hu)", fd, net_s, node_s, ntohs(ipxaddr.sa_socket));
|
||||
|
||||
if(ptr->flags & IPX_BOUND) {
|
||||
log_printf("bind failed: socket already bound");
|
||||
RETURN_WSA(WSAEINVAL, -1);
|
||||
}
|
||||
|
||||
/* 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!
|
||||
*/
|
||||
|
||||
unsigned char z6[] = {0,0,0,0,0,0};
|
||||
struct ipx_interface *nic = nics;
|
||||
|
||||
while(nic) {
|
||||
if(
|
||||
(memcmp(ipxaddr->sa_netnum, nic->ipx_net, 4) == 0 || memcmp(ipxaddr->sa_netnum, z6, 4) == 0) &&
|
||||
(memcmp(ipxaddr->sa_nodenum, nic->ipx_node, 6) == 0 || memcmp(ipxaddr->sa_nodenum, z6, 6) == 0)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
nic = nic->next;
|
||||
if(router_bind(router, 0, fd, &ipxaddr, &(ptr->nic_bcast)) == -1) {
|
||||
RETURN(-1);
|
||||
}
|
||||
|
||||
if(!nic) {
|
||||
log_printf("bind failed: no such address");
|
||||
RETURN_WSA(WSAEADDRNOTAVAIL, -1);
|
||||
}
|
||||
NET_TO_STRING(net_s, ipxaddr.sa_netnum);
|
||||
NODE_TO_STRING(node_s, ipxaddr.sa_nodenum);
|
||||
|
||||
ptr->nic = nic;
|
||||
|
||||
if(ipxaddr->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;
|
||||
ipx_socket *socket = sockets;
|
||||
|
||||
while(socket) {
|
||||
if(ntohs(socket->socket) == s && socket->flags & IPX_BOUND) {
|
||||
if(s == 65535) {
|
||||
log_printf("bind failed: out of sockets?!");
|
||||
RETURN_WSA(WSAEADDRNOTAVAIL, -1);
|
||||
}
|
||||
|
||||
s++;
|
||||
socket = sockets;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
socket = socket->next;
|
||||
}
|
||||
|
||||
ptr->socket = htons(s);
|
||||
}else{
|
||||
/* Test if any bound socket is using the requested socket number. */
|
||||
|
||||
ipx_socket *socket = sockets;
|
||||
|
||||
while(socket) {
|
||||
if(socket->socket == ipxaddr->sa_socket && socket->flags & IPX_BOUND) {
|
||||
log_printf("bind failed: requested socket in use");
|
||||
RETURN_WSA(WSAEADDRINUSE, -1);
|
||||
}
|
||||
|
||||
socket = socket->next;
|
||||
}
|
||||
|
||||
ptr->socket = ipxaddr->sa_socket;
|
||||
}
|
||||
|
||||
NET_TO_STRING(net_s, nic->ipx_net);
|
||||
NODE_TO_STRING(node_s, nic->ipx_node);
|
||||
|
||||
log_printf("bind address: net=%s node=%s socket=%hu", net_s, node_s, ntohs(ptr->socket));
|
||||
|
||||
/* TODO: Bind fake socket in socket() call rather than here?
|
||||
*
|
||||
* I think I put the bind() call for it here so that the fd given to the
|
||||
* program would be in the expected un-bound state, although I'm not sure
|
||||
* if there are any winsock calls it could ONLY make on such a socket.
|
||||
*/
|
||||
log_printf("bind address: net=%s node=%s socket=%hu", net_s, node_s, ntohs(ipxaddr.sa_socket));
|
||||
|
||||
struct sockaddr_in bind_addr;
|
||||
bind_addr.sin_family = AF_INET;
|
||||
bind_addr.sin_port = 0;
|
||||
bind_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
bind_addr.sin_port = 0;
|
||||
|
||||
int rval = r_bind(fd, (struct sockaddr*)&bind_addr, sizeof(bind_addr));
|
||||
|
||||
if(rval == 0) {
|
||||
ptr->flags |= IPX_BOUND;
|
||||
}else{
|
||||
log_printf("Binding fake socket failed: %s", w32_error(WSAGetLastError()));
|
||||
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);
|
||||
RETURN(-1);
|
||||
}
|
||||
|
||||
RETURN(rval);
|
||||
int al = sizeof(bind_addr);
|
||||
|
||||
if(r_getsockname(fd, (struct sockaddr*)&bind_addr, &al) == -1) {
|
||||
log_printf("getsockname failed: %s", w32_error(WSAGetLastError()));
|
||||
|
||||
router_unbind(router, 0, fd);
|
||||
RETURN(-1);
|
||||
}
|
||||
|
||||
memcpy(&(ptr->addr), &ipxaddr, sizeof(ipxaddr));
|
||||
ptr->flags |= IPX_BOUND;
|
||||
|
||||
router_set_port(router, 0, fd, bind_addr.sin_port);
|
||||
|
||||
RETURN(0);
|
||||
}else{
|
||||
RETURN(r_bind(fd, addr, addrlen));
|
||||
}
|
||||
@ -326,61 +268,10 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen) {
|
||||
* Attempts to bind socket 0 will really bind socket 0
|
||||
*/
|
||||
int ipx_ex_bind(SOCKET fd, const struct sockaddr_ipx *ipxaddr) {
|
||||
ipx_socket *ptr = get_socket(fd);
|
||||
|
||||
if(!ipxaddr) {
|
||||
/* Call with NULL address to remove extra bind */
|
||||
log_printf("ipx_ex_bind(%d, NULL)", fd);
|
||||
|
||||
ptr->flags &= ~IPX_EX_BOUND;
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
char net_s[12], node_s[18];
|
||||
|
||||
NET_TO_STRING(net_s, ipxaddr->sa_netnum);
|
||||
NODE_TO_STRING(node_s, ipxaddr->sa_nodenum);
|
||||
|
||||
log_printf("ipx_ex_bind(%d, net=%s node=%s socket=%hu)", fd, net_s, node_s, ntohs(ipxaddr->sa_socket));
|
||||
|
||||
if(!(ptr->flags & IPX_BOUND)) {
|
||||
log_printf("ipx_ex_bind: Socket is not bound");
|
||||
RETURN_WSA(WSAEINVAL, -1);
|
||||
}
|
||||
|
||||
unsigned char z6[] = {0,0,0,0,0,0};
|
||||
struct ipx_interface *nic = nics;
|
||||
|
||||
while(nic) {
|
||||
if(
|
||||
(memcmp(ipxaddr->sa_netnum, nic->ipx_net, 4) == 0 || memcmp(ipxaddr->sa_netnum, z6, 4) == 0) &&
|
||||
(memcmp(ipxaddr->sa_nodenum, nic->ipx_node, 6) == 0 || memcmp(ipxaddr->sa_nodenum, z6, 6) == 0)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
nic = nic->next;
|
||||
}
|
||||
|
||||
if(!nic) {
|
||||
log_printf("ipx_ex_bind: no such address");
|
||||
RETURN_WSA(WSAEADDRNOTAVAIL, -1);
|
||||
}
|
||||
|
||||
NET_TO_STRING(net_s, nic->ipx_net);
|
||||
NODE_TO_STRING(node_s, nic->ipx_node);
|
||||
|
||||
log_printf("bind address: net=%s node=%s socket=%hu", net_s, node_s, ntohs(ipxaddr->sa_socket));
|
||||
|
||||
ptr->ex_nic = nic;
|
||||
ptr->ex_socket = ipxaddr->sa_socket;
|
||||
ptr->flags |= IPX_EX_BOUND;
|
||||
|
||||
RETURN(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WSAAPI getsockname(SOCKET fd, struct sockaddr *addr, int *addrlen) {
|
||||
struct sockaddr_ipx *ipxaddr = (struct sockaddr_ipx*)addr;
|
||||
ipx_socket *ptr = get_socket(fd);
|
||||
|
||||
if(ptr) {
|
||||
@ -390,11 +281,7 @@ int WSAAPI getsockname(SOCKET fd, struct sockaddr *addr, int *addrlen) {
|
||||
RETURN_WSA(WSAEFAULT, -1);
|
||||
}
|
||||
|
||||
ipxaddr->sa_family = AF_IPX;
|
||||
memcpy(ipxaddr->sa_netnum, ptr->nic->ipx_net, 4);
|
||||
memcpy(ipxaddr->sa_nodenum, ptr->nic->ipx_node, 6);
|
||||
ipxaddr->sa_socket = ptr->socket;
|
||||
|
||||
memcpy(addr, &(ptr->addr), sizeof(ptr->addr));
|
||||
*addrlen = sizeof(struct sockaddr_ipx);
|
||||
|
||||
RETURN(0);
|
||||
@ -629,11 +516,16 @@ int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval,
|
||||
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;
|
||||
|
||||
router_set_filter(router, 0, fd, -1);
|
||||
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
@ -705,12 +597,12 @@ int WSAAPI sendto(SOCKET fd, const char *buf, int len, int flags, const struct s
|
||||
unsigned char z6[] = {0,0,0,0,0,0};
|
||||
|
||||
if(memcmp(packet->dest_net, z6, 4) == 0) {
|
||||
memcpy(packet->dest_net, sockptr->nic->ipx_net, 4);
|
||||
memcpy(packet->dest_net, sockptr->addr.sa_netnum, 4);
|
||||
}
|
||||
|
||||
memcpy(packet->src_net, sockptr->nic->ipx_net, 4);
|
||||
memcpy(packet->src_node, sockptr->nic->ipx_node, 6);
|
||||
packet->src_socket = sockptr->socket;
|
||||
memcpy(packet->src_net, sockptr->addr.sa_netnum, 4);
|
||||
memcpy(packet->src_node, sockptr->addr.sa_nodenum, 6);
|
||||
packet->src_socket = sockptr->addr.sa_socket;
|
||||
|
||||
packet->size = htons(len);
|
||||
memcpy(packet->data, buf, len);
|
||||
@ -720,7 +612,7 @@ int WSAAPI sendto(SOCKET fd, const char *buf, int len, int flags, const struct s
|
||||
struct sockaddr_in saddr;
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(global_conf.udp_port);
|
||||
saddr.sin_addr.s_addr = (host ? host->ipaddr : (global_conf.bcast_all ? INADDR_BROADCAST : sockptr->nic->bcast));
|
||||
saddr.sin_addr.s_addr = (host ? host->ipaddr : (global_conf.bcast_all ? INADDR_BROADCAST : sockptr->nic_bcast));
|
||||
|
||||
int sval = r_sendto(net_fd, (char*)packet, psize, 0, (struct sockaddr*)&saddr, sizeof(saddr));
|
||||
if(sval == -1) {
|
||||
@ -744,6 +636,7 @@ int PASCAL shutdown(SOCKET fd, int cmd) {
|
||||
|
||||
if(cmd == SD_RECEIVE || cmd == SD_BOTH) {
|
||||
sockptr->flags &= ~IPX_RECV;
|
||||
router_set_port(router, 0, fd, 0);
|
||||
}
|
||||
|
||||
RETURN(0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user