mirror of
https://github.com/solemnwarning/ipxwrapper
synced 2024-12-30 16:45:37 +01:00
Implemented new "address table" code for maintaining address uniqueness between
multiple IPXWrapper processes without needing a shared router thread. Replaced router/rclient code with a single, per-process router thread. Add addresses to the cache in the router main loop rather than winsock recv functions. Packets are no longer preceeded by an rpacket_header structure when relayed to the local UDP sockets. Each IPXWrapper instance creates a "private" UDP socket bound to a random port on INADDR_ANY which is used for sending all packets and receiving unicast. Bugfix: Check source socket number before relaying to a connected socket.
This commit is contained in:
parent
8dc0d0aaa3
commit
920b5ee2c3
3
Makefile
3
Makefile
@ -33,7 +33,8 @@ export CXXFLAGS
|
|||||||
VERSION := DEVELOPMENT BUILD
|
VERSION := DEVELOPMENT BUILD
|
||||||
|
|
||||||
IPXWRAPPER_DEPS := src/ipxwrapper.o src/winsock.o src/ipxwrapper_stubs.o src/log.o src/common.o \
|
IPXWRAPPER_DEPS := src/ipxwrapper.o src/winsock.o src/ipxwrapper_stubs.o src/log.o src/common.o \
|
||||||
src/interface.o src/router.o src/ipxwrapper.def src/addrcache.o src/config.o src/addr.o
|
src/interface.o src/router.o src/ipxwrapper.def src/addrcache.o src/config.o src/addr.o \
|
||||||
|
src/addrtable.o
|
||||||
|
|
||||||
BIN_FILES := changes.txt license.txt readme.txt ipxwrapper.dll mswsock.dll wsock32.dll ipxconfig.exe \
|
BIN_FILES := changes.txt license.txt readme.txt ipxwrapper.dll mswsock.dll wsock32.dll ipxconfig.exe \
|
||||||
ipxrouter.exe dpwsockx.dll directplay-win32.reg directplay-win64.reg
|
ipxrouter.exe dpwsockx.dll directplay-win32.reg directplay-win64.reg
|
||||||
|
416
src/addrtable.c
Normal file
416
src/addrtable.c
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
/* IPXWrapper - Address table
|
||||||
|
* Copyright (C) 2008-2012 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The address table is used to co-ordinate the IPX addresses in use accross all
|
||||||
|
* IPXWrapper instances.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
|
||||||
|
#include "addrtable.h"
|
||||||
|
#include "ipxwrapper.h"
|
||||||
|
|
||||||
|
#define ADDR_TABLE_SIZE (sizeof(addr_table_header_t) + (ADDR_TABLE_MAX_ENTRIES * sizeof(addr_table_entry_t)))
|
||||||
|
|
||||||
|
static HANDLE addr_table_mutex = NULL;
|
||||||
|
|
||||||
|
static HANDLE addr_table_h = NULL;
|
||||||
|
|
||||||
|
static addr_table_header_t *addr_table_header = NULL;
|
||||||
|
static addr_table_entry_t *addr_table_base = NULL;
|
||||||
|
|
||||||
|
static void _init_fail(void)
|
||||||
|
{
|
||||||
|
if(addr_table_mutex)
|
||||||
|
{
|
||||||
|
ReleaseMutex(addr_table_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_printf(LOG_WARNING, "Multiple processes may have address conflicts!");
|
||||||
|
addr_table_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addr_table_init(void)
|
||||||
|
{
|
||||||
|
/* Mutex used to protect the address table. */
|
||||||
|
if(!(addr_table_mutex = CreateMutex(NULL, FALSE, ADDR_TABLE_MUTEX)))
|
||||||
|
{
|
||||||
|
log_printf(LOG_ERROR, "Failed to create/open mutex: %s", w32_error(GetLastError()));
|
||||||
|
_init_fail();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_table_lock();
|
||||||
|
|
||||||
|
/* Allocate the address table "file" (shared memory). */
|
||||||
|
|
||||||
|
if(!(addr_table_h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, ADDR_TABLE_SIZE, ADDR_TABLE_NAME)))
|
||||||
|
{
|
||||||
|
log_printf(LOG_ERROR, "Failed to create/open address table: %s", w32_error(GetLastError()));
|
||||||
|
_init_fail();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* True if the table didn't exist before we created it. */
|
||||||
|
bool new_table = (GetLastError() != ERROR_ALREADY_EXISTS);
|
||||||
|
|
||||||
|
/* Map the address table. */
|
||||||
|
if(!(addr_table_header = MapViewOfFile(addr_table_h, FILE_MAP_WRITE, 0, 0, ADDR_TABLE_SIZE)))
|
||||||
|
{
|
||||||
|
log_printf(LOG_ERROR, "Failed to map address table: %s", w32_error(GetLastError()));
|
||||||
|
_init_fail();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(new_table)
|
||||||
|
{
|
||||||
|
/* Initialise the address table. */
|
||||||
|
|
||||||
|
memset(addr_table_header, 0, ADDR_TABLE_SIZE);
|
||||||
|
|
||||||
|
addr_table_header->version = ADDR_TABLE_VERSION;
|
||||||
|
}
|
||||||
|
else if(addr_table_header->version != ADDR_TABLE_VERSION)
|
||||||
|
{
|
||||||
|
log_printf(LOG_ERROR, "Address table from incompatible IPXWrapper version present");
|
||||||
|
_init_fail();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release all handles to the address table and associated objects. */
|
||||||
|
void addr_table_cleanup(void)
|
||||||
|
{
|
||||||
|
if(addr_table_header)
|
||||||
|
{
|
||||||
|
UnmapViewOfFile(addr_table_header);
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_table_header = NULL;
|
||||||
|
addr_table_base = NULL;
|
||||||
|
|
||||||
|
if(addr_table_h)
|
||||||
|
{
|
||||||
|
CloseHandle(addr_table_h);
|
||||||
|
addr_table_h = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr_table_mutex)
|
||||||
|
{
|
||||||
|
CloseHandle(addr_table_mutex);
|
||||||
|
addr_table_mutex = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addr_table_lock(void)
|
||||||
|
{
|
||||||
|
if(addr_table_mutex)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(addr_table_mutex, INFINITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addr_table_unlock(void)
|
||||||
|
{
|
||||||
|
if(addr_table_mutex)
|
||||||
|
{
|
||||||
|
ReleaseMutex(addr_table_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search the address table for any conflicting binds. Falls back to searching
|
||||||
|
* the sockets table if the address table is unavailable.
|
||||||
|
*
|
||||||
|
* Returns false if a conflict was confirmed, true otherwise.
|
||||||
|
*/
|
||||||
|
bool addr_table_check(const struct sockaddr_ipx *addr, bool reuse)
|
||||||
|
{
|
||||||
|
if(addr_table_base)
|
||||||
|
{
|
||||||
|
addr_table_lock();
|
||||||
|
|
||||||
|
addr_table_entry_t *entry = addr_table_base;
|
||||||
|
addr_table_entry_t *end = addr_table_base + ADDR_TABLE_MAX_ENTRIES;
|
||||||
|
|
||||||
|
while(entry < end && (entry->flags & ADDR_TABLE_ENTRY_VALID))
|
||||||
|
{
|
||||||
|
if(addr->sa_socket == entry->socket && (!(entry->flags & ADDR_TABLE_ENTRY_REUSE) || !reuse))
|
||||||
|
{
|
||||||
|
/* A socket is already bound to this address and either
|
||||||
|
* it or this one doesn't have SO_REUSEADDR set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
addr_table_unlock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry++;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_table_unlock();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
/* Address table is unavailable, check the sockets table
|
||||||
|
* instead. This will not maintain address uniqueness between
|
||||||
|
* multiple processes!
|
||||||
|
*/
|
||||||
|
|
||||||
|
lock_sockets();
|
||||||
|
|
||||||
|
ipx_socket *s = sockets;
|
||||||
|
|
||||||
|
for(; s; s = s->next)
|
||||||
|
{
|
||||||
|
if(memcmp(&(s->addr), addr, sizeof(struct sockaddr_ipx)) == 0 && (!(s->flags & IPX_REUSE) || !reuse))
|
||||||
|
{
|
||||||
|
unlock_sockets();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock_sockets();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return an unused socket number in network byte order for automatic allocation,
|
||||||
|
* zero if none are available.
|
||||||
|
*/
|
||||||
|
uint16_t addr_table_auto_socket(void)
|
||||||
|
{
|
||||||
|
/* 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 sock = 1024;
|
||||||
|
|
||||||
|
if(addr_table_base)
|
||||||
|
{
|
||||||
|
addr_table_lock();
|
||||||
|
|
||||||
|
addr_table_entry_t *entry = addr_table_base;
|
||||||
|
addr_table_entry_t *end = addr_table_base + ADDR_TABLE_MAX_ENTRIES;
|
||||||
|
|
||||||
|
while(entry < end)
|
||||||
|
{
|
||||||
|
if(ntohs(sock) == entry->socket)
|
||||||
|
{
|
||||||
|
if(sock == 65535)
|
||||||
|
{
|
||||||
|
addr_table_unlock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock++;
|
||||||
|
|
||||||
|
entry = addr_table_base;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry++;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_table_unlock();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
lock_sockets();
|
||||||
|
|
||||||
|
ipx_socket *s = sockets;
|
||||||
|
|
||||||
|
while(s)
|
||||||
|
{
|
||||||
|
if((s->flags & IPX_BOUND) && ntohs(sock) == s->addr.sa_socket)
|
||||||
|
{
|
||||||
|
if(sock == 65535)
|
||||||
|
{
|
||||||
|
unlock_sockets();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock++;
|
||||||
|
|
||||||
|
s = sockets;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = s->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock_sockets();
|
||||||
|
}
|
||||||
|
|
||||||
|
return htons(sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert an entry into the address table.
|
||||||
|
*
|
||||||
|
* Performs no conflict checking. Take the address table lock in the caller and
|
||||||
|
* use addr_table_check() before calling this.
|
||||||
|
*/
|
||||||
|
void addr_table_add(const struct sockaddr_ipx *addr, uint16_t port, bool reuse)
|
||||||
|
{
|
||||||
|
if(!addr_table_base)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_table_lock();
|
||||||
|
|
||||||
|
/* Iterate over the address table to find the last entry. */
|
||||||
|
|
||||||
|
addr_table_entry_t *entry = addr_table_base;
|
||||||
|
addr_table_entry_t *end = addr_table_base + ADDR_TABLE_MAX_ENTRIES;
|
||||||
|
|
||||||
|
while(entry < end && (entry->flags & ADDR_TABLE_ENTRY_VALID))
|
||||||
|
{
|
||||||
|
entry++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append the new address to the address table. */
|
||||||
|
|
||||||
|
if(entry < end)
|
||||||
|
{
|
||||||
|
entry->netnum = addr32_in(addr->sa_netnum);
|
||||||
|
entry->nodenum = addr48_in(addr->sa_nodenum);
|
||||||
|
entry->socket = addr->sa_socket;
|
||||||
|
|
||||||
|
entry->flags = ADDR_TABLE_ENTRY_VALID;
|
||||||
|
|
||||||
|
if(reuse)
|
||||||
|
{
|
||||||
|
entry->flags |= ADDR_TABLE_ENTRY_REUSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->port = port;
|
||||||
|
entry->time = time(NULL);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
log_printf(LOG_ERROR, "Out of address table slots, not appending!");
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_table_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove an entry from the address table. */
|
||||||
|
void addr_table_remove(uint16_t port)
|
||||||
|
{
|
||||||
|
if(!addr_table_base)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_table_lock();
|
||||||
|
|
||||||
|
/* Iterate over the address table until we find the correct entry... */
|
||||||
|
|
||||||
|
addr_table_entry_t *entry = addr_table_base;
|
||||||
|
addr_table_entry_t *end = addr_table_base + ADDR_TABLE_MAX_ENTRIES;
|
||||||
|
|
||||||
|
while(entry < end && (entry->flags & ADDR_TABLE_ENTRY_VALID) && entry->port != port)
|
||||||
|
{
|
||||||
|
entry++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Continue iteration until we find the last entry... */
|
||||||
|
|
||||||
|
addr_table_entry_t *last = entry;
|
||||||
|
|
||||||
|
while(last < end && (last->flags & ADDR_TABLE_ENTRY_VALID))
|
||||||
|
{
|
||||||
|
last++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Replace entry with the last entry and mark the latter as invalid. */
|
||||||
|
|
||||||
|
if(entry < end)
|
||||||
|
{
|
||||||
|
*entry = *last;
|
||||||
|
|
||||||
|
last->flags &= ~ADDR_TABLE_ENTRY_VALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_table_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the time field for any of our entries in the address table and remove
|
||||||
|
* any that have expired (most likely a crashed process).
|
||||||
|
*/
|
||||||
|
void addr_table_update(void)
|
||||||
|
{
|
||||||
|
if(!addr_table_base)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_sockets();
|
||||||
|
|
||||||
|
addr_table_lock();
|
||||||
|
|
||||||
|
ipx_socket *sock = sockets;
|
||||||
|
|
||||||
|
/* Remove any expired entries. */
|
||||||
|
|
||||||
|
addr_table_entry_t *entry = addr_table_base;
|
||||||
|
addr_table_entry_t *last = addr_table_base;
|
||||||
|
addr_table_entry_t *end = addr_table_base + ADDR_TABLE_MAX_ENTRIES;
|
||||||
|
|
||||||
|
while(last < end && (last->flags & ADDR_TABLE_ENTRY_VALID))
|
||||||
|
{
|
||||||
|
last++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(; entry < end && (entry->flags & ADDR_TABLE_ENTRY_VALID); entry++)
|
||||||
|
{
|
||||||
|
if(entry->time + ADDR_TABLE_ENTRY_TIMEOUT <= time(NULL))
|
||||||
|
{
|
||||||
|
*end = *last;
|
||||||
|
|
||||||
|
last->flags &= ~ADDR_TABLE_ENTRY_VALID;
|
||||||
|
last--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is really, really efficient. */
|
||||||
|
|
||||||
|
for(; sock; sock = sock->next)
|
||||||
|
{
|
||||||
|
if(sock->flags & IPX_BOUND)
|
||||||
|
{
|
||||||
|
/* Search the address table... */
|
||||||
|
|
||||||
|
for(entry = addr_table_base; entry < end && (entry->flags & ADDR_TABLE_ENTRY_VALID); entry++)
|
||||||
|
{
|
||||||
|
if(entry->port == sock->port)
|
||||||
|
{
|
||||||
|
entry->time = time(NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_table_unlock();
|
||||||
|
|
||||||
|
unlock_sockets();
|
||||||
|
}
|
72
src/addrtable.h
Normal file
72
src/addrtable.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/* IPXWrapper - Address table
|
||||||
|
* Copyright (C) 2008-2012 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ADDRTABLE_H
|
||||||
|
#define ADDRTABLE_H
|
||||||
|
|
||||||
|
#include <wsipx.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "addr.h"
|
||||||
|
|
||||||
|
#define ADDR_TABLE_MAX_ENTRIES 512
|
||||||
|
#define ADDR_TABLE_ENTRY_TIMEOUT 10
|
||||||
|
|
||||||
|
#define ADDR_TABLE_MUTEX "IPXWrapper_addr_table_mutex"
|
||||||
|
#define ADDR_TABLE_NAME "IPXWrapper_addr_table"
|
||||||
|
|
||||||
|
#define ADDR_TABLE_VERSION 1
|
||||||
|
|
||||||
|
typedef struct addr_table_header addr_table_header_t;
|
||||||
|
|
||||||
|
struct addr_table_header
|
||||||
|
{
|
||||||
|
int version;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ADDR_TABLE_ENTRY_VALID ((int)(1<<0))
|
||||||
|
#define ADDR_TABLE_ENTRY_REUSE ((int)(1<<1))
|
||||||
|
|
||||||
|
typedef struct addr_table_entry addr_table_entry_t;
|
||||||
|
|
||||||
|
struct addr_table_entry
|
||||||
|
{
|
||||||
|
addr32_t netnum;
|
||||||
|
addr48_t nodenum;
|
||||||
|
uint16_t socket;
|
||||||
|
|
||||||
|
int flags;
|
||||||
|
uint16_t port;
|
||||||
|
time_t time;
|
||||||
|
};
|
||||||
|
|
||||||
|
void addr_table_init(void);
|
||||||
|
void addr_table_cleanup(void);
|
||||||
|
|
||||||
|
void addr_table_lock(void);
|
||||||
|
void addr_table_unlock(void);
|
||||||
|
|
||||||
|
bool addr_table_check(const struct sockaddr_ipx *addr, bool reuse);
|
||||||
|
uint16_t addr_table_auto_socket(void);
|
||||||
|
|
||||||
|
void addr_table_add(const struct sockaddr_ipx *addr, uint16_t port, bool reuse);
|
||||||
|
void addr_table_remove(uint16_t port);
|
||||||
|
|
||||||
|
void addr_table_update(void);
|
||||||
|
|
||||||
|
#endif /* !ADDRTABLE_H */
|
@ -68,7 +68,11 @@ HKEY reg_open_subkey(HKEY parent, const char *path, bool readwrite)
|
|||||||
|
|
||||||
if(err != ERROR_SUCCESS)
|
if(err != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
log_printf(LOG_ERROR, "Could not open registry: %s", w32_error(err));
|
if(err != ERROR_FILE_NOT_FOUND)
|
||||||
|
{
|
||||||
|
log_printf(LOG_ERROR, "Could not open registry: %s", w32_error(err));
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,11 +41,8 @@ struct ipaddr_list {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ipx_socket *sockets = NULL;
|
ipx_socket *sockets = NULL;
|
||||||
SOCKET send_fd = -1;
|
|
||||||
main_config_t main_config;
|
main_config_t main_config;
|
||||||
|
|
||||||
struct rclient g_rclient;
|
|
||||||
|
|
||||||
static CRITICAL_SECTION sockets_cs;
|
static CRITICAL_SECTION sockets_cs;
|
||||||
|
|
||||||
static void init_cs(CRITICAL_SECTION *cs)
|
static void init_cs(CRITICAL_SECTION *cs)
|
||||||
@ -57,14 +54,17 @@ static void init_cs(CRITICAL_SECTION *cs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res) {
|
BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res)
|
||||||
if(why == DLL_PROCESS_ATTACH) {
|
{
|
||||||
|
if(why == DLL_PROCESS_ATTACH)
|
||||||
|
{
|
||||||
log_open("ipxwrapper.log");
|
log_open("ipxwrapper.log");
|
||||||
|
|
||||||
log_printf(LOG_INFO, "IPXWrapper %s", version_string);
|
log_printf(LOG_INFO, "IPXWrapper %s", version_string);
|
||||||
log_printf(LOG_INFO, "Compiled at %s", compile_time);
|
log_printf(LOG_INFO, "Compiled at %s", compile_time);
|
||||||
|
|
||||||
if(!getenv("SystemRoot")) {
|
if(!getenv("SystemRoot"))
|
||||||
|
{
|
||||||
log_printf(LOG_WARNING, "SystemRoot is not set in the environment");
|
log_printf(LOG_WARNING, "SystemRoot is not set in the environment");
|
||||||
|
|
||||||
char env[268] = "SystemRoot=";
|
char env[268] = "SystemRoot=";
|
||||||
@ -81,51 +81,21 @@ BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res) {
|
|||||||
|
|
||||||
ipx_interfaces_init();
|
ipx_interfaces_init();
|
||||||
|
|
||||||
if(!rclient_init(&g_rclient)) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_cs(&sockets_cs);
|
init_cs(&sockets_cs);
|
||||||
|
|
||||||
WSADATA wsdata;
|
WSADATA wsdata;
|
||||||
int err = WSAStartup(MAKEWORD(1,1), &wsdata);
|
int err = WSAStartup(MAKEWORD(1,1), &wsdata);
|
||||||
if(err) {
|
if(err)
|
||||||
|
{
|
||||||
log_printf(LOG_ERROR, "Failed to initialize winsock: %s", w32_error(err));
|
log_printf(LOG_ERROR, "Failed to initialize winsock: %s", w32_error(err));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!rclient_start(&g_rclient)) {
|
router_init();
|
||||||
return FALSE;
|
}
|
||||||
}
|
else if(why == DLL_PROCESS_DETACH)
|
||||||
|
{
|
||||||
if(g_rclient.router) {
|
router_cleanup();
|
||||||
send_fd = g_rclient.router->udp_sock;
|
|
||||||
}else{
|
|
||||||
/* Create UDP socket for sending packets if not using a private router */
|
|
||||||
|
|
||||||
if((send_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
|
|
||||||
log_printf(LOG_ERROR, "Failed to create UDP socket: %s", w32_error(WSAGetLastError()));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
addr.sin_port = 0;
|
|
||||||
|
|
||||||
if(bind(send_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
|
|
||||||
log_printf(LOG_ERROR, "Failed to bind UDP socket (send_fd): %s", w32_error(WSAGetLastError()));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else if(why == DLL_PROCESS_DETACH) {
|
|
||||||
if(send_fd != -1 && !g_rclient.router) {
|
|
||||||
closesocket(send_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
send_fd = -1;
|
|
||||||
|
|
||||||
rclient_stop(&g_rclient);
|
|
||||||
|
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
|
|
||||||
|
@ -52,11 +52,15 @@
|
|||||||
|
|
||||||
typedef struct ipx_socket ipx_socket;
|
typedef struct ipx_socket ipx_socket;
|
||||||
typedef struct ipx_packet ipx_packet;
|
typedef struct ipx_packet ipx_packet;
|
||||||
typedef struct ipx_host ipx_host;
|
|
||||||
|
|
||||||
struct ipx_socket {
|
struct ipx_socket {
|
||||||
SOCKET fd;
|
SOCKET fd;
|
||||||
|
|
||||||
|
/* Locally bound UDP port number (Network byte order).
|
||||||
|
* Undefined before IPX bind() call.
|
||||||
|
*/
|
||||||
|
uint16_t port;
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
uint8_t s_ptype;
|
uint8_t s_ptype;
|
||||||
uint8_t f_ptype; /* Undefined when IPX_FILTER isn't set */
|
uint8_t f_ptype; /* Undefined when IPX_FILTER isn't set */
|
||||||
@ -85,20 +89,8 @@ struct ipx_packet {
|
|||||||
char data[1];
|
char data[1];
|
||||||
} __attribute__((__packed__));
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
struct ipx_host {
|
|
||||||
unsigned char ipx_net[4];
|
|
||||||
unsigned char ipx_node[6];
|
|
||||||
|
|
||||||
uint32_t ipaddr;
|
|
||||||
time_t last_packet;
|
|
||||||
|
|
||||||
ipx_host *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern ipx_socket *sockets;
|
extern ipx_socket *sockets;
|
||||||
extern SOCKET send_fd;
|
|
||||||
extern main_config_t main_config;
|
extern main_config_t main_config;
|
||||||
extern struct rclient g_rclient;
|
|
||||||
|
|
||||||
ipx_socket *get_socket(SOCKET fd);
|
ipx_socket *get_socket(SOCKET fd);
|
||||||
void lock_sockets(void);
|
void lock_sockets(void);
|
||||||
|
1196
src/router.c
1196
src/router.c
File diff suppressed because it is too large
Load Diff
100
src/router.h
100
src/router.h
@ -23,102 +23,10 @@
|
|||||||
#include <wsipx.h>
|
#include <wsipx.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define MAX_ROUTER_CLIENTS 128
|
extern SOCKET shared_socket;
|
||||||
|
extern SOCKET private_socket;
|
||||||
|
|
||||||
struct router_call {
|
void router_init(void);
|
||||||
enum {
|
void router_cleanup(void);
|
||||||
rc_bind,
|
|
||||||
rc_unbind,
|
|
||||||
rc_port,
|
|
||||||
rc_filter,
|
|
||||||
rc_flags,
|
|
||||||
rc_remote
|
|
||||||
} call;
|
|
||||||
|
|
||||||
SOCKET sock;
|
|
||||||
|
|
||||||
struct sockaddr_ipx arg_addr;
|
|
||||||
int arg_int;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct router_ret {
|
|
||||||
int err_code; /* ERROR_SUCCESS on success */
|
|
||||||
|
|
||||||
struct sockaddr_ipx ret_addr;
|
|
||||||
uint32_t ret_u32;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Represents a bound IPX address */
|
|
||||||
struct router_addr {
|
|
||||||
struct sockaddr_ipx addr;
|
|
||||||
|
|
||||||
uint16_t local_port; /* Local UDP port (NETWORK BYTE ORDER) */
|
|
||||||
SOCKET ws_socket; /* Application socket */
|
|
||||||
SOCKET control_socket; /* Control socket */
|
|
||||||
int filter_ptype; /* Packet type filter, negative to disable */
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
/* Only accept packets from this address (any if AF_UNSPEC) */
|
|
||||||
struct sockaddr_ipx remote_addr;
|
|
||||||
|
|
||||||
struct router_addr *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct router_client {
|
|
||||||
SOCKET sock;
|
|
||||||
|
|
||||||
struct router_call recvbuf;
|
|
||||||
int recvbuf_len;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct router_vars {
|
|
||||||
BOOL running;
|
|
||||||
|
|
||||||
SOCKET udp_sock;
|
|
||||||
SOCKET listener;
|
|
||||||
|
|
||||||
struct router_client clients[MAX_ROUTER_CLIENTS];
|
|
||||||
int client_count;
|
|
||||||
|
|
||||||
WSAEVENT wsa_event;
|
|
||||||
|
|
||||||
CRITICAL_SECTION crit_sec;
|
|
||||||
BOOL crit_sec_init;
|
|
||||||
|
|
||||||
struct router_addr *addrs;
|
|
||||||
|
|
||||||
char *recvbuf;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rclient {
|
|
||||||
CRITICAL_SECTION cs;
|
|
||||||
BOOL cs_init;
|
|
||||||
|
|
||||||
SOCKET sock;
|
|
||||||
|
|
||||||
struct router_vars *router;
|
|
||||||
HANDLE thread;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rpacket_header {
|
|
||||||
uint32_t src_ipaddr;
|
|
||||||
char spare[20];
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
|
|
||||||
struct router_vars *router_init(BOOL global);
|
|
||||||
void router_destroy(struct router_vars *router);
|
|
||||||
|
|
||||||
DWORD router_main(void *arg);
|
|
||||||
|
|
||||||
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, 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_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 */
|
#endif /* !IPXWRAPPER_ROUTER_H */
|
||||||
|
232
src/winsock.c
232
src/winsock.c
@ -27,6 +27,7 @@
|
|||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "router.h"
|
#include "router.h"
|
||||||
#include "addrcache.h"
|
#include "addrcache.h"
|
||||||
|
#include "addrtable.h"
|
||||||
|
|
||||||
typedef struct _PROTOCOL_INFO {
|
typedef struct _PROTOCOL_INFO {
|
||||||
DWORD dwServiceFlags ;
|
DWORD dwServiceFlags ;
|
||||||
@ -205,8 +206,9 @@ int WSAAPI closesocket(SOCKET fd) {
|
|||||||
|
|
||||||
log_printf(LOG_INFO, "IPX socket closed (fd = %d)", fd);
|
log_printf(LOG_INFO, "IPX socket closed (fd = %d)", fd);
|
||||||
|
|
||||||
if(ptr->flags & IPX_BOUND) {
|
if(ptr->flags & IPX_BOUND)
|
||||||
rclient_unbind(&g_rclient, fd);
|
{
|
||||||
|
addr_table_remove(ptr->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ptr == sockets) {
|
if(ptr == sockets) {
|
||||||
@ -228,13 +230,76 @@ int WSAAPI closesocket(SOCKET fd) {
|
|||||||
RETURN(0);
|
RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen) {
|
static bool _complete_bind_address(struct sockaddr_ipx *addr)
|
||||||
ipx_socket *ptr = get_socket(fd);
|
{
|
||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* If you know the above information about IPX socket numbers to be incorrect,
|
||||||
|
* PLEASE email me with corrections!
|
||||||
|
*/
|
||||||
|
|
||||||
if(ptr) {
|
/* Iterate over the interfaces list, stop at the first match. */
|
||||||
|
|
||||||
|
struct ipx_interface *ifaces = get_ipx_interfaces(), *iface;
|
||||||
|
|
||||||
|
addr32_t netnum = addr32_in(addr->sa_netnum);
|
||||||
|
addr48_t nodenum = addr48_in(addr->sa_nodenum);
|
||||||
|
|
||||||
|
for(iface = ifaces; iface; iface = iface->next)
|
||||||
|
{
|
||||||
|
if(
|
||||||
|
(netnum == iface->ipx_net || netnum == 0)
|
||||||
|
&& (nodenum == iface->ipx_node || nodenum == 0)
|
||||||
|
) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!iface)
|
||||||
|
{
|
||||||
|
log_printf(LOG_ERROR, "bind failed: no such address");
|
||||||
|
|
||||||
|
free_ipx_interface_list(&ifaces);
|
||||||
|
|
||||||
|
WSASetLastError(WSAEADDRNOTAVAIL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr32_out(addr->sa_netnum, iface->ipx_net);
|
||||||
|
addr48_out(addr->sa_nodenum, iface->ipx_node);
|
||||||
|
|
||||||
|
free_ipx_interface_list(&ifaces);
|
||||||
|
|
||||||
|
/* Socket zero signifies automatic allocation. */
|
||||||
|
|
||||||
|
if(addr->sa_socket == 0 && (addr->sa_socket = addr_table_auto_socket()) == 0)
|
||||||
|
{
|
||||||
|
/* Hmmm. We appear to have ran out of sockets?! */
|
||||||
|
|
||||||
|
log_printf(LOG_ERROR, "bind failed: out of sockets?!");
|
||||||
|
|
||||||
|
WSASetLastError(WSAEADDRNOTAVAIL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen)
|
||||||
|
{
|
||||||
|
ipx_socket *sock = get_socket(fd);
|
||||||
|
|
||||||
|
if(sock)
|
||||||
|
{
|
||||||
struct sockaddr_ipx ipxaddr;
|
struct sockaddr_ipx ipxaddr;
|
||||||
|
|
||||||
if(addrlen < sizeof(ipxaddr)) {
|
if(addrlen < sizeof(ipxaddr) || addr->sa_family != AF_IPX)
|
||||||
|
{
|
||||||
RETURN_WSA(WSAEFAULT, -1);
|
RETURN_WSA(WSAEFAULT, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,52 +309,108 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen) {
|
|||||||
|
|
||||||
log_printf(LOG_INFO, "bind(%d, %s)", fd, req_addr_s);
|
log_printf(LOG_INFO, "bind(%d, %s)", fd, req_addr_s);
|
||||||
|
|
||||||
if(ptr->flags & IPX_BOUND) {
|
if(sock->flags & IPX_BOUND)
|
||||||
|
{
|
||||||
log_printf(LOG_ERROR, "bind failed: socket already bound");
|
log_printf(LOG_ERROR, "bind failed: socket already bound");
|
||||||
RETURN_WSA(WSAEINVAL, -1);
|
|
||||||
|
unlock_sockets();
|
||||||
|
|
||||||
|
WSASetLastError(WSAEINVAL);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!rclient_bind(&g_rclient, fd, &ipxaddr, ptr->flags)) {
|
addr_table_lock();
|
||||||
RETURN(-1);
|
|
||||||
|
/* Resolve any wildcards in the requested address. */
|
||||||
|
|
||||||
|
if(!_complete_bind_address(&ipxaddr))
|
||||||
|
{
|
||||||
|
addr_table_unlock();
|
||||||
|
unlock_sockets();
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPX_STRING_ADDR(got_addr_s, addr32_in(ipxaddr.sa_netnum), addr48_in(ipxaddr.sa_nodenum), ipxaddr.sa_socket);
|
IPX_STRING_ADDR(got_addr_s, addr32_in(ipxaddr.sa_netnum), addr48_in(ipxaddr.sa_nodenum), ipxaddr.sa_socket);
|
||||||
|
|
||||||
log_printf(LOG_INFO, "bind address: %s", got_addr_s);
|
log_printf(LOG_INFO, "bind address: %s", got_addr_s);
|
||||||
|
|
||||||
struct sockaddr_in bind_addr;
|
/* Check that the address is free. */
|
||||||
bind_addr.sin_family = AF_INET;
|
|
||||||
bind_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
||||||
bind_addr.sin_port = 0;
|
|
||||||
|
|
||||||
if(r_bind(fd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) == -1) {
|
if(!addr_table_check(&ipxaddr, !!(sock->flags & IPX_REUSE)))
|
||||||
log_printf(LOG_ERROR, "Binding local UDP socket failed: %s", w32_error(WSAGetLastError()));
|
{
|
||||||
|
/* Address has already been bound. */
|
||||||
|
|
||||||
rclient_unbind(&g_rclient, fd);
|
addr_table_unlock();
|
||||||
RETURN(-1);
|
unlock_sockets();
|
||||||
|
|
||||||
|
WSASetLastError(WSAEADDRINUSE);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Bind the fake (UDP) socket. */
|
||||||
|
|
||||||
|
struct sockaddr_in bind_addr;
|
||||||
|
|
||||||
|
bind_addr.sin_family = AF_INET;
|
||||||
|
bind_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
bind_addr.sin_port = 0;
|
||||||
|
|
||||||
|
if(r_bind(fd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) == -1)
|
||||||
|
{
|
||||||
|
log_printf(
|
||||||
|
LOG_ERROR,
|
||||||
|
"Binding local UDP socket failed: %s",
|
||||||
|
w32_error(WSAGetLastError())
|
||||||
|
);
|
||||||
|
|
||||||
|
addr_table_unlock();
|
||||||
|
unlock_sockets();
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find out what port we got allocated. */
|
||||||
|
|
||||||
int al = sizeof(bind_addr);
|
int al = sizeof(bind_addr);
|
||||||
|
|
||||||
if(r_getsockname(fd, (struct sockaddr*)&bind_addr, &al) == -1) {
|
if(r_getsockname(fd, (struct sockaddr*)&bind_addr, &al) == -1)
|
||||||
log_printf(LOG_ERROR, "getsockname failed: %s", w32_error(WSAGetLastError()));
|
{
|
||||||
|
/* Socket state is now inconsistent as the underlying
|
||||||
|
* UDP socket has been bound, but the IPX socket failed
|
||||||
|
* to bind.
|
||||||
|
*
|
||||||
|
* We also don't know what port number the socket is
|
||||||
|
* bound to and can't unbind, so future bind attempts
|
||||||
|
* will fail.
|
||||||
|
*/
|
||||||
|
|
||||||
rclient_unbind(&g_rclient, fd);
|
log_printf(LOG_ERROR, "getsockname: %s", w32_error(WSAGetLastError()));
|
||||||
RETURN(-1);
|
log_printf(LOG_WARNING, "SOCKET STATE IS NOW INCONSISTENT!");
|
||||||
|
|
||||||
|
addr_table_unlock();
|
||||||
|
unlock_sockets();
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_printf(LOG_DEBUG, "Bound to local UDP port %hu", ntohs(bind_addr.sin_port));
|
sock->port = bind_addr.sin_port;
|
||||||
|
|
||||||
memcpy(&(ptr->addr), &ipxaddr, sizeof(ipxaddr));
|
log_printf(LOG_DEBUG, "Bound to local UDP port %hu", ntohs(sock->port));
|
||||||
ptr->flags |= IPX_BOUND;
|
|
||||||
|
|
||||||
if(ptr->flags & IPX_RECV) {
|
/* Add to the address table. */
|
||||||
rclient_set_port(&g_rclient, fd, bind_addr.sin_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
rclient_set_filter(&g_rclient, fd, ptr->flags & IPX_FILTER ? ptr->f_ptype : -1);
|
addr_table_add(&ipxaddr, sock->port, !!(sock->flags & IPX_REUSE));
|
||||||
|
|
||||||
RETURN(0);
|
/* Mark the IPX socket as bound. */
|
||||||
|
|
||||||
|
memcpy(&(sock->addr), &ipxaddr, sizeof(ipxaddr));
|
||||||
|
sock->flags |= IPX_BOUND;
|
||||||
|
|
||||||
|
addr_table_unlock();
|
||||||
|
unlock_sockets();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}else{
|
}else{
|
||||||
return r_bind(fd, addr, addrlen);
|
return r_bind(fd, addr, addrlen);
|
||||||
}
|
}
|
||||||
@ -317,8 +438,6 @@ int WSAAPI getsockname(SOCKET fd, struct sockaddr *addr, int *addrlen) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RECVBUF_SIZE (sizeof(struct rpacket_header) + MAX_PKT_SIZE)
|
|
||||||
|
|
||||||
/* Recieve a packet from an IPX socket
|
/* Recieve a packet from an IPX socket
|
||||||
* addr must be NULL or a region of memory big enough for a sockaddr_ipx
|
* addr must be NULL or a region of memory big enough for a sockaddr_ipx
|
||||||
*
|
*
|
||||||
@ -337,22 +456,22 @@ static int recv_packet(ipx_socket *sockptr, char *buf, int bufsize, int flags, s
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *recvbuf = malloc(RECVBUF_SIZE);
|
char *recvbuf = malloc(MAX_PKT_SIZE);
|
||||||
if(!recvbuf) {
|
if(!recvbuf) {
|
||||||
WSASetLastError(ERROR_OUTOFMEMORY);
|
WSASetLastError(ERROR_OUTOFMEMORY);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rpacket_header *rp_header = (struct rpacket_header*)recvbuf;
|
struct ipx_packet *packet = (struct ipx_packet*)(recvbuf);
|
||||||
struct ipx_packet *packet = (struct ipx_packet*)(recvbuf + sizeof(*rp_header));
|
|
||||||
|
|
||||||
int rval = r_recv(fd, recvbuf, RECVBUF_SIZE, flags);
|
int rval = r_recv(fd, recvbuf, MAX_PKT_SIZE, flags);
|
||||||
if(rval == -1) {
|
if(rval == -1) {
|
||||||
free(recvbuf);
|
free(recvbuf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rval < sizeof(*rp_header) + sizeof(ipx_packet) - 1 || rval != sizeof(*rp_header) + packet->size + sizeof(ipx_packet) - 1) {
|
if(rval < sizeof(ipx_packet) - 1 || rval != packet->size + sizeof(ipx_packet) - 1)
|
||||||
|
{
|
||||||
log_printf(LOG_ERROR, "Invalid packet received on loopback port!");
|
log_printf(LOG_ERROR, "Invalid packet received on loopback port!");
|
||||||
|
|
||||||
free(recvbuf);
|
free(recvbuf);
|
||||||
@ -367,15 +486,6 @@ static int recv_packet(ipx_socket *sockptr, char *buf, int bufsize, int flags, s
|
|||||||
log_printf(LOG_DEBUG, "Received packet from %s", addr_s);
|
log_printf(LOG_DEBUG, "Received packet from %s", addr_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Move full sockaddr into rp_header? */
|
|
||||||
|
|
||||||
struct sockaddr_in real_addr;
|
|
||||||
real_addr.sin_family = AF_INET;
|
|
||||||
real_addr.sin_addr.s_addr = rp_header->src_ipaddr;
|
|
||||||
real_addr.sin_port = htons(main_config.udp_port);
|
|
||||||
|
|
||||||
addr_cache_set((struct sockaddr*)&real_addr, sizeof(real_addr), addr32_in(packet->src_net), addr48_in(packet->src_node), 0);
|
|
||||||
|
|
||||||
if(addr) {
|
if(addr) {
|
||||||
addr->sa_family = AF_IPX;
|
addr->sa_family = AF_IPX;
|
||||||
memcpy(addr->sa_netnum, packet->src_net, 4);
|
memcpy(addr->sa_netnum, packet->src_net, 4);
|
||||||
@ -611,11 +721,6 @@ int WSAAPI getsockopt(SOCKET fd, int level, int optname, char FAR *optval, int F
|
|||||||
sockptr->flags &= ~(flag); \
|
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 WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval, int optlen) {
|
||||||
int *intval = (int*)optval;
|
int *intval = (int*)optval;
|
||||||
BOOL *bval = (BOOL*)optval;
|
BOOL *bval = (BOOL*)optval;
|
||||||
@ -649,10 +754,6 @@ int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(optname == IPX_FILTERPTYPE) {
|
if(optname == IPX_FILTERPTYPE) {
|
||||||
if(sockptr->flags & IPX_BOUND && !rclient_set_filter(&g_rclient, fd, *intval)) {
|
|
||||||
RETURN(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
sockptr->f_ptype = *intval;
|
sockptr->f_ptype = *intval;
|
||||||
sockptr->flags |= IPX_FILTER;
|
sockptr->flags |= IPX_FILTER;
|
||||||
|
|
||||||
@ -660,17 +761,12 @@ int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(optname == IPX_STOPFILTERPTYPE) {
|
if(optname == IPX_STOPFILTERPTYPE) {
|
||||||
if(sockptr->flags & IPX_BOUND && !rclient_set_filter(&g_rclient, fd, -1)) {
|
|
||||||
RETURN(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
sockptr->flags &= ~IPX_FILTER;
|
sockptr->flags &= ~IPX_FILTER;
|
||||||
|
|
||||||
RETURN(0);
|
RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(optname == IPX_RECEIVE_BROADCAST) {
|
if(optname == IPX_RECEIVE_BROADCAST) {
|
||||||
RC_SET_FLAG(IPX_RECV_BCAST, *bval);
|
|
||||||
SET_FLAG(IPX_RECV_BCAST, *bval);
|
SET_FLAG(IPX_RECV_BCAST, *bval);
|
||||||
|
|
||||||
RETURN(0);
|
RETURN(0);
|
||||||
@ -688,14 +784,12 @@ int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval,
|
|||||||
|
|
||||||
if(level == SOL_SOCKET) {
|
if(level == SOL_SOCKET) {
|
||||||
if(optname == SO_BROADCAST) {
|
if(optname == SO_BROADCAST) {
|
||||||
RC_SET_FLAG(IPX_BROADCAST, *bval);
|
|
||||||
SET_FLAG(IPX_BROADCAST, *bval);
|
SET_FLAG(IPX_BROADCAST, *bval);
|
||||||
|
|
||||||
RETURN(0);
|
RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(optname == SO_REUSEADDR) {
|
if(optname == SO_REUSEADDR) {
|
||||||
RC_SET_FLAG(IPX_REUSE, *bval);
|
|
||||||
SET_FLAG(IPX_REUSE, *bval);
|
SET_FLAG(IPX_REUSE, *bval);
|
||||||
|
|
||||||
RETURN(0);
|
RETURN(0);
|
||||||
@ -727,7 +821,7 @@ static int send_packet(const ipx_packet *packet, int len, struct sockaddr *addr,
|
|||||||
log_printf(LOG_DEBUG, "Sending packet to %s (%s:%hu)", addr_s, inet_ntoa(v4->sin_addr), ntohs(v4->sin_port));
|
log_printf(LOG_DEBUG, "Sending packet to %s (%s:%hu)", addr_s, inet_ntoa(v4->sin_addr), ntohs(v4->sin_port));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (r_sendto(send_fd, (char*)packet, len, 0, addr, addrlen) == len);
|
return (r_sendto(private_socket, (char*)packet, len, 0, addr, addrlen) == len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int WSAAPI sendto(SOCKET fd, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen) {
|
int WSAAPI sendto(SOCKET fd, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen) {
|
||||||
@ -872,10 +966,6 @@ int PASCAL shutdown(SOCKET fd, int cmd) {
|
|||||||
|
|
||||||
if(sockptr) {
|
if(sockptr) {
|
||||||
if(cmd == SD_RECEIVE || cmd == SD_BOTH) {
|
if(cmd == SD_RECEIVE || cmd == SD_BOTH) {
|
||||||
if(sockptr->flags & IPX_BOUND && !rclient_set_port(&g_rclient, fd, 0)) {
|
|
||||||
RETURN(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
sockptr->flags &= ~IPX_RECV;
|
sockptr->flags &= ~IPX_RECV;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -945,10 +1035,6 @@ int PASCAL connect(SOCKET fd, const struct sockaddr *addr, int addrlen) {
|
|||||||
struct sockaddr_ipx dc_addr;
|
struct sockaddr_ipx dc_addr;
|
||||||
dc_addr.sa_family = AF_UNSPEC;
|
dc_addr.sa_family = AF_UNSPEC;
|
||||||
|
|
||||||
if(!rclient_set_remote(&g_rclient, fd, &dc_addr)) {
|
|
||||||
RETURN(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
sockptr->flags &= ~IPX_CONNECTED;
|
sockptr->flags &= ~IPX_CONNECTED;
|
||||||
|
|
||||||
RETURN(0);
|
RETURN(0);
|
||||||
@ -973,10 +1059,6 @@ int PASCAL connect(SOCKET fd, const struct sockaddr *addr, int addrlen) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!rclient_set_remote(&g_rclient, fd, ipxaddr)) {
|
|
||||||
RETURN(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&(sockptr->remote_addr), addr, sizeof(*ipxaddr));
|
memcpy(&(sockptr->remote_addr), addr, sizeof(*ipxaddr));
|
||||||
sockptr->flags |= IPX_CONNECTED;
|
sockptr->flags |= IPX_CONNECTED;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user