mirror of
https://github.com/solemnwarning/ipxwrapper
synced 2024-12-30 16:45:37 +01:00
Refactor address conflict detection.
Detect multiple sockets bound to the same address within a session by creating a named mutex. Multiple handles to a mutex may exist and closing the last one destroys it.
This commit is contained in:
parent
3c13aab8e5
commit
043ce1495e
2
Makefile
2
Makefile
@ -36,7 +36,7 @@ VERSION := git
|
|||||||
|
|
||||||
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 src/firewall.o src/wpcap_stubs.o
|
src/firewall.o src/wpcap_stubs.o
|
||||||
|
|
||||||
BIN_FILES := $(shell cat manifest.bin.txt)
|
BIN_FILES := $(shell cat manifest.bin.txt)
|
||||||
SRC_FILES := $(shell cat manifest.src.txt)
|
SRC_FILES := $(shell cat manifest.src.txt)
|
||||||
|
442
src/addrtable.c
442
src/addrtable.c
@ -1,442 +0,0 @@
|
|||||||
/* IPXWrapper - Address table
|
|
||||||
* Copyright (C) 2008-2014 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 <uthash.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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the last entry in the address table.
|
|
||||||
* Returns addr_table_base if there are none.
|
|
||||||
*/
|
|
||||||
static addr_table_entry_t *_last_entry()
|
|
||||||
{
|
|
||||||
addr_table_entry_t *last = addr_table_base, *next = addr_table_base + 1;
|
|
||||||
addr_table_entry_t *end = addr_table_base + ADDR_TABLE_MAX_ENTRIES;
|
|
||||||
|
|
||||||
while(next < end && next->flags & ADDR_TABLE_ENTRY_VALID)
|
|
||||||
{
|
|
||||||
last = next++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return last;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr_table_base = (addr_table_entry_t*)(addr_table_header + 1);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr_table_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void addr_table_cleanup(void)
|
|
||||||
{
|
|
||||||
/* Release any remaining addresses bound by this process. */
|
|
||||||
|
|
||||||
if(addr_table_base)
|
|
||||||
{
|
|
||||||
ipx_socket *s, *tmp;
|
|
||||||
|
|
||||||
HASH_ITER(hh, sockets, s, tmp)
|
|
||||||
{
|
|
||||||
if(s->flags & IPX_BOUND)
|
|
||||||
{
|
|
||||||
addr_table_remove(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close handles to the address table. */
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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, *tmp;
|
|
||||||
|
|
||||||
HASH_ITER(hh, sockets, s, tmp)
|
|
||||||
{
|
|
||||||
if(memcmp(&(s->addr), addr, sizeof(struct sockaddr_ipx)) == 0)
|
|
||||||
{
|
|
||||||
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, *tmp;
|
|
||||||
|
|
||||||
HASH_ITER(hh, sockets, s, tmp)
|
|
||||||
{
|
|
||||||
if((s->flags & IPX_BOUND) && ntohs(sock) == s->addr.sa_socket)
|
|
||||||
{
|
|
||||||
if(sock == 65535)
|
|
||||||
{
|
|
||||||
unlock_sockets();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sock++;
|
|
||||||
|
|
||||||
s = sockets;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ipx_socket *sock)
|
|
||||||
{
|
|
||||||
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(sock->addr.sa_netnum);
|
|
||||||
entry->nodenum = addr48_in(sock->addr.sa_nodenum);
|
|
||||||
entry->socket = sock->addr.sa_socket;
|
|
||||||
|
|
||||||
if(sock->flags & IPX_IS_SPXII)
|
|
||||||
{
|
|
||||||
entry->type = ADDR_TABLE_TYPE_SPXII;
|
|
||||||
}
|
|
||||||
else if(sock->flags & IPX_IS_SPX)
|
|
||||||
{
|
|
||||||
entry->type = ADDR_TABLE_TYPE_SPX;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
entry->type = ADDR_TABLE_TYPE_IPX;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry->process = GetCurrentProcessId();
|
|
||||||
entry->sock = sock->fd;
|
|
||||||
|
|
||||||
entry->flags = ADDR_TABLE_ENTRY_VALID;
|
|
||||||
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(const ipx_socket *sock)
|
|
||||||
{
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
if(entry->process == GetCurrentProcessId() && entry->sock == sock->fd)
|
|
||||||
{
|
|
||||||
addr_table_entry_t *last = _last_entry();
|
|
||||||
|
|
||||||
*entry = *last;
|
|
||||||
last->flags &= ~ADDR_TABLE_ENTRY_VALID;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
++entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
/* Remove any expired entries. */
|
|
||||||
|
|
||||||
addr_table_entry_t *entry = addr_table_base;
|
|
||||||
addr_table_entry_t *last = _last_entry();
|
|
||||||
addr_table_entry_t *end = addr_table_base + ADDR_TABLE_MAX_ENTRIES;
|
|
||||||
|
|
||||||
for(; entry < end && (entry->flags & ADDR_TABLE_ENTRY_VALID); entry++)
|
|
||||||
{
|
|
||||||
if(entry->time + ADDR_TABLE_ENTRY_TIMEOUT <= time(NULL))
|
|
||||||
{
|
|
||||||
*entry = *last;
|
|
||||||
|
|
||||||
last->flags &= ~ADDR_TABLE_ENTRY_VALID;
|
|
||||||
last--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is really, really efficient. */
|
|
||||||
|
|
||||||
ipx_socket *sock, *tmp;
|
|
||||||
|
|
||||||
HASH_ITER(hh, sockets, sock, tmp)
|
|
||||||
{
|
|
||||||
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->process == GetCurrentProcessId() && entry->sock == sock->fd)
|
|
||||||
{
|
|
||||||
entry->time = time(NULL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addr_table_unlock();
|
|
||||||
|
|
||||||
unlock_sockets();
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
/* IPXWrapper - Address table
|
|
||||||
* Copyright (C) 2008-2014 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"
|
|
||||||
#include "ipxwrapper.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 2
|
|
||||||
|
|
||||||
typedef struct addr_table_header addr_table_header_t;
|
|
||||||
|
|
||||||
struct addr_table_header
|
|
||||||
{
|
|
||||||
int version;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ADDR_TABLE_ENTRY_VALID ((int)(1<<0))
|
|
||||||
|
|
||||||
typedef struct addr_table_entry addr_table_entry_t;
|
|
||||||
|
|
||||||
struct addr_table_entry
|
|
||||||
{
|
|
||||||
addr32_t netnum;
|
|
||||||
addr48_t nodenum;
|
|
||||||
uint16_t socket;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
ADDR_TABLE_TYPE_IPX,
|
|
||||||
ADDR_TABLE_TYPE_SPX,
|
|
||||||
ADDR_TABLE_TYPE_SPXII
|
|
||||||
} type;
|
|
||||||
|
|
||||||
DWORD process;
|
|
||||||
int sock;
|
|
||||||
|
|
||||||
int flags;
|
|
||||||
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);
|
|
||||||
uint16_t addr_table_auto_socket(void);
|
|
||||||
|
|
||||||
void addr_table_add(const ipx_socket *sock);
|
|
||||||
void addr_table_remove(const ipx_socket *sock);
|
|
||||||
|
|
||||||
void addr_table_update(void);
|
|
||||||
|
|
||||||
#endif /* !ADDRTABLE_H */
|
|
@ -31,7 +31,6 @@
|
|||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "router.h"
|
#include "router.h"
|
||||||
#include "addrcache.h"
|
#include "addrcache.h"
|
||||||
#include "addrtable.h"
|
|
||||||
|
|
||||||
int _putenv(const char *envstring);
|
int _putenv(const char *envstring);
|
||||||
|
|
||||||
@ -104,16 +103,12 @@ BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_table_init();
|
|
||||||
|
|
||||||
router_init();
|
router_init();
|
||||||
}
|
}
|
||||||
else if(why == DLL_PROCESS_DETACH)
|
else if(why == DLL_PROCESS_DETACH)
|
||||||
{
|
{
|
||||||
router_cleanup();
|
router_cleanup();
|
||||||
|
|
||||||
addr_table_cleanup();
|
|
||||||
|
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
|
|
||||||
DeleteCriticalSection(&sockets_cs);
|
DeleteCriticalSection(&sockets_cs);
|
||||||
|
@ -66,6 +66,7 @@ struct ipx_socket {
|
|||||||
|
|
||||||
/* The following values are undefined when IPX_BOUND is not set */
|
/* The following values are undefined when IPX_BOUND is not set */
|
||||||
struct sockaddr_ipx addr;
|
struct sockaddr_ipx addr;
|
||||||
|
HANDLE sock_mut;
|
||||||
|
|
||||||
/* Address used with connect call, only set when IPX_CONNECTED is */
|
/* Address used with connect call, only set when IPX_CONNECTED is */
|
||||||
struct sockaddr_ipx remote_addr;
|
struct sockaddr_ipx remote_addr;
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
#include "ipxwrapper.h"
|
#include "ipxwrapper.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "addrcache.h"
|
#include "addrcache.h"
|
||||||
#include "addrtable.h"
|
|
||||||
|
|
||||||
static bool router_running = false;
|
static bool router_running = false;
|
||||||
static WSAEVENT router_event = WSA_INVALID_EVENT;
|
static WSAEVENT router_event = WSA_INVALID_EVENT;
|
||||||
@ -552,8 +551,6 @@ static DWORD router_main(void *arg)
|
|||||||
{
|
{
|
||||||
DWORD exit_status = 0;
|
DWORD exit_status = 0;
|
||||||
|
|
||||||
time_t last_at_update = 0;
|
|
||||||
|
|
||||||
ipx_interface_t *interfaces = NULL;
|
ipx_interface_t *interfaces = NULL;
|
||||||
|
|
||||||
HANDLE *wait_events = &router_event;
|
HANDLE *wait_events = &router_event;
|
||||||
@ -597,12 +594,6 @@ static DWORD router_main(void *arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(last_at_update != time(NULL))
|
|
||||||
{
|
|
||||||
addr_table_update();
|
|
||||||
last_at_update = time(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ipx_use_pcap)
|
if(ipx_use_pcap)
|
||||||
{
|
{
|
||||||
ipx_interface_t *i;
|
ipx_interface_t *i;
|
||||||
|
152
src/winsock.c
152
src/winsock.c
@ -27,7 +27,6 @@
|
|||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "router.h"
|
#include "router.h"
|
||||||
#include "addrcache.h"
|
#include "addrcache.h"
|
||||||
#include "addrtable.h"
|
|
||||||
|
|
||||||
#define XP_CONNECTIONLESS 0x00000001
|
#define XP_CONNECTIONLESS 0x00000001
|
||||||
#define XP_GUARANTEED_DELIVERY 0x00000002
|
#define XP_GUARANTEED_DELIVERY 0x00000002
|
||||||
@ -420,7 +419,7 @@ int WSAAPI closesocket(SOCKET sockfd)
|
|||||||
|
|
||||||
if(sock->flags & IPX_BOUND)
|
if(sock->flags & IPX_BOUND)
|
||||||
{
|
{
|
||||||
addr_table_remove(sock);
|
CloseHandle(sock->sock_mut);
|
||||||
}
|
}
|
||||||
|
|
||||||
HASH_DEL(sockets, sock);
|
HASH_DEL(sockets, sock);
|
||||||
@ -431,7 +430,59 @@ int WSAAPI closesocket(SOCKET sockfd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _complete_bind_address(struct sockaddr_ipx *addr)
|
static HANDLE _open_socket_mutex(uint16_t socket, bool exclusive)
|
||||||
|
{
|
||||||
|
char mutex_name[256];
|
||||||
|
snprintf(mutex_name, sizeof(mutex_name), "ipxwrapper_socket_%hu", socket);
|
||||||
|
|
||||||
|
HANDLE mutex = CreateMutex(NULL, FALSE, mutex_name);
|
||||||
|
if(!mutex)
|
||||||
|
{
|
||||||
|
log_printf(LOG_ERROR, "Error when creating mutex %s: %s",
|
||||||
|
mutex_name, w32_error(GetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(GetLastError() == ERROR_ALREADY_EXISTS && exclusive)
|
||||||
|
{
|
||||||
|
CloseHandle(mutex);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _complete_bind(ipx_socket *sock)
|
||||||
|
{
|
||||||
|
if(ntohs(sock->addr.sa_socket) == 0)
|
||||||
|
{
|
||||||
|
uint16_t socknum = 1024;
|
||||||
|
|
||||||
|
do {
|
||||||
|
HANDLE mutex = _open_socket_mutex(socknum, true);
|
||||||
|
if(mutex)
|
||||||
|
{
|
||||||
|
sock->addr.sa_socket = htons(socknum);
|
||||||
|
sock->sock_mut = mutex;
|
||||||
|
sock->flags |= IPX_BOUND;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while(socknum++ != 65535);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if((sock->sock_mut = _open_socket_mutex(
|
||||||
|
ntohs(sock->addr.sa_socket), !(sock->flags & IPX_REUSE))))
|
||||||
|
{
|
||||||
|
sock->flags |= IPX_BOUND;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _resolve_bind_address(ipx_socket *sock, const struct sockaddr_ipx *addr)
|
||||||
{
|
{
|
||||||
/* Network number 00:00:00:00 is specified as the "current" network, this code
|
/* 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.
|
* treats it as a wildcard when used for the network OR node numbers.
|
||||||
@ -466,28 +517,14 @@ static bool _complete_bind_address(struct sockaddr_ipx *addr)
|
|||||||
log_printf(LOG_ERROR, "bind failed: no such address");
|
log_printf(LOG_ERROR, "bind failed: no such address");
|
||||||
|
|
||||||
free_ipx_interface_list(&ifaces);
|
free_ipx_interface_list(&ifaces);
|
||||||
|
|
||||||
WSASetLastError(WSAEADDRNOTAVAIL);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr32_out(addr->sa_netnum, iface->ipx_net);
|
addr32_out(sock->addr.sa_netnum, iface->ipx_net);
|
||||||
addr48_out(addr->sa_nodenum, iface->ipx_node);
|
addr48_out(sock->addr.sa_nodenum, iface->ipx_node);
|
||||||
|
sock->addr.sa_socket = addr->sa_socket;
|
||||||
|
|
||||||
free_ipx_interface_list(&ifaces);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,38 +560,30 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_table_lock();
|
|
||||||
|
|
||||||
/* Resolve any wildcards in the requested address. */
|
/* Resolve any wildcards in the requested address. */
|
||||||
|
|
||||||
if(!_complete_bind_address(&ipxaddr))
|
if(!_resolve_bind_address(sock, &ipxaddr))
|
||||||
{
|
{
|
||||||
addr_table_unlock();
|
|
||||||
unlock_sockets();
|
unlock_sockets();
|
||||||
|
|
||||||
|
WSASetLastError(WSAEADDRNOTAVAIL);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
/* Check that the address is free. */
|
/* Check that the address is free. */
|
||||||
|
|
||||||
if(!(sock->flags & IPX_REUSE) && !addr_table_check(&ipxaddr))
|
if(!_complete_bind(sock))
|
||||||
{
|
{
|
||||||
/* Address has already been bound. */
|
|
||||||
|
|
||||||
log_printf(LOG_ERROR, "bind failed: address already in use");
|
|
||||||
|
|
||||||
WSASetLastError(WSAEADDRINUSE);
|
|
||||||
|
|
||||||
addr_table_unlock();
|
|
||||||
unlock_sockets();
|
unlock_sockets();
|
||||||
|
|
||||||
|
WSASetLastError(WSAEADDRINUSE);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IPX_STRING_ADDR(got_addr_s, addr32_in(sock->addr.sa_netnum), addr48_in(sock->addr.sa_nodenum), sock->addr.sa_socket);
|
||||||
|
|
||||||
|
log_printf(LOG_INFO, "bind address: %s", got_addr_s);
|
||||||
|
|
||||||
/* Bind the underlying socket. */
|
/* Bind the underlying socket. */
|
||||||
|
|
||||||
struct sockaddr_in bind_addr;
|
struct sockaddr_in bind_addr;
|
||||||
@ -567,7 +596,9 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen)
|
|||||||
{
|
{
|
||||||
log_printf(LOG_ERROR, "Binding local socket failed: %s", w32_error(WSAGetLastError()));
|
log_printf(LOG_ERROR, "Binding local socket failed: %s", w32_error(WSAGetLastError()));
|
||||||
|
|
||||||
addr_table_unlock();
|
CloseHandle(sock->sock_mut);
|
||||||
|
sock->flags &= ~IPX_BOUND;
|
||||||
|
|
||||||
unlock_sockets();
|
unlock_sockets();
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@ -590,26 +621,17 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen)
|
|||||||
log_printf(LOG_ERROR, "Cannot get local port of socket: %s", w32_error(WSAGetLastError()));
|
log_printf(LOG_ERROR, "Cannot get local port of socket: %s", w32_error(WSAGetLastError()));
|
||||||
log_printf(LOG_WARNING, "Socket %d is NOW INCONSISTENT!", fd);
|
log_printf(LOG_WARNING, "Socket %d is NOW INCONSISTENT!", fd);
|
||||||
|
|
||||||
addr_table_unlock();
|
CloseHandle(sock->sock_mut);
|
||||||
|
sock->flags &= ~IPX_BOUND;
|
||||||
|
|
||||||
unlock_sockets();
|
unlock_sockets();
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sock->port = bind_addr.sin_port;
|
sock->port = bind_addr.sin_port;
|
||||||
|
|
||||||
log_printf(LOG_DEBUG, "Bound to local port %hu", ntohs(sock->port));
|
log_printf(LOG_DEBUG, "Bound to local port %hu", ntohs(sock->port));
|
||||||
|
|
||||||
/* Mark the IPX socket as bound and insert it into the address
|
|
||||||
* table.
|
|
||||||
*/
|
|
||||||
|
|
||||||
memcpy(&(sock->addr), &ipxaddr, sizeof(ipxaddr));
|
|
||||||
sock->flags |= IPX_BOUND;
|
|
||||||
|
|
||||||
addr_table_add(sock);
|
|
||||||
|
|
||||||
addr_table_unlock();
|
|
||||||
unlock_sockets();
|
unlock_sockets();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1959,26 +1981,16 @@ static int _connect_spx(ipx_socket *sock, struct sockaddr_ipx *ipxaddr)
|
|||||||
|
|
||||||
/* The sa_netnum and sa_nodenum fields are filled out above. */
|
/* The sa_netnum and sa_nodenum fields are filled out above. */
|
||||||
|
|
||||||
addr_table_lock();
|
if(!_complete_bind(sock))
|
||||||
|
|
||||||
if((sock->addr.sa_socket = addr_table_auto_socket()) != 0)
|
|
||||||
{
|
{
|
||||||
sock->flags |= IPX_BOUND;
|
|
||||||
|
|
||||||
addr_table_add(sock);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
log_printf(LOG_ERROR, "Cannot allocate socket number for SPX socket");
|
log_printf(LOG_ERROR, "Cannot allocate socket number for SPX socket");
|
||||||
log_printf(LOG_WARNING, "Socket %d is NOW INCONSISTENT!", sock->fd);
|
log_printf(LOG_WARNING, "Socket %d is NOW INCONSISTENT!", sock->fd);
|
||||||
|
|
||||||
addr_table_unlock();
|
|
||||||
unlock_sockets();
|
unlock_sockets();
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_table_unlock();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
IPX_STRING_ADDR(
|
IPX_STRING_ADDR(
|
||||||
addr_s,
|
addr_s,
|
||||||
@ -2311,6 +2323,25 @@ SOCKET PASCAL accept(SOCKET s, struct sockaddr *addr, int *addrlen)
|
|||||||
|
|
||||||
nsock->addr = sock->addr;
|
nsock->addr = sock->addr;
|
||||||
|
|
||||||
|
/* Duplicate the mutex handle held by the listening
|
||||||
|
* socket used to detect address collisions. There is no
|
||||||
|
* way to recover from an error here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(!(DuplicateHandle(GetCurrentProcess(), sock->sock_mut,
|
||||||
|
GetCurrentProcess(), &(nsock->sock_mut),
|
||||||
|
0, FALSE, DUPLICATE_SAME_ACCESS)))
|
||||||
|
{
|
||||||
|
log_printf(LOG_ERROR, "Could not duplicate socket mutex: %s", w32_error(GetLastError()));
|
||||||
|
|
||||||
|
closesocket(nsock->fd);
|
||||||
|
free(nsock);
|
||||||
|
unlock_sockets();
|
||||||
|
|
||||||
|
WSASetLastError(WSAENETDOWN);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Copy remote address from the spxinit packet. */
|
/* Copy remote address from the spxinit packet. */
|
||||||
|
|
||||||
nsock->remote_addr.sa_family = AF_IPX;
|
nsock->remote_addr.sa_family = AF_IPX;
|
||||||
@ -2319,7 +2350,6 @@ SOCKET PASCAL accept(SOCKET s, struct sockaddr *addr, int *addrlen)
|
|||||||
nsock->remote_addr.sa_socket = spxinit.socket;
|
nsock->remote_addr.sa_socket = spxinit.socket;
|
||||||
|
|
||||||
HASH_ADD_INT(sockets, fd, nsock);
|
HASH_ADD_INT(sockets, fd, nsock);
|
||||||
addr_table_add(nsock);
|
|
||||||
|
|
||||||
if(addr)
|
if(addr)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user