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 \
|
||||
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)
|
||||
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 "router.h"
|
||||
#include "addrcache.h"
|
||||
#include "addrtable.h"
|
||||
|
||||
int _putenv(const char *envstring);
|
||||
|
||||
@ -104,16 +103,12 @@ BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
addr_table_init();
|
||||
|
||||
router_init();
|
||||
}
|
||||
else if(why == DLL_PROCESS_DETACH)
|
||||
{
|
||||
router_cleanup();
|
||||
|
||||
addr_table_cleanup();
|
||||
|
||||
WSACleanup();
|
||||
|
||||
DeleteCriticalSection(&sockets_cs);
|
||||
|
@ -66,6 +66,7 @@ struct ipx_socket {
|
||||
|
||||
/* The following values are undefined when IPX_BOUND is not set */
|
||||
struct sockaddr_ipx addr;
|
||||
HANDLE sock_mut;
|
||||
|
||||
/* Address used with connect call, only set when IPX_CONNECTED is */
|
||||
struct sockaddr_ipx remote_addr;
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "ipxwrapper.h"
|
||||
#include "interface.h"
|
||||
#include "addrcache.h"
|
||||
#include "addrtable.h"
|
||||
|
||||
static bool router_running = false;
|
||||
static WSAEVENT router_event = WSA_INVALID_EVENT;
|
||||
@ -552,8 +551,6 @@ static DWORD router_main(void *arg)
|
||||
{
|
||||
DWORD exit_status = 0;
|
||||
|
||||
time_t last_at_update = 0;
|
||||
|
||||
ipx_interface_t *interfaces = NULL;
|
||||
|
||||
HANDLE *wait_events = &router_event;
|
||||
@ -597,12 +594,6 @@ static DWORD router_main(void *arg)
|
||||
break;
|
||||
}
|
||||
|
||||
if(last_at_update != time(NULL))
|
||||
{
|
||||
addr_table_update();
|
||||
last_at_update = time(NULL);
|
||||
}
|
||||
|
||||
if(ipx_use_pcap)
|
||||
{
|
||||
ipx_interface_t *i;
|
||||
|
152
src/winsock.c
152
src/winsock.c
@ -27,7 +27,6 @@
|
||||
#include "interface.h"
|
||||
#include "router.h"
|
||||
#include "addrcache.h"
|
||||
#include "addrtable.h"
|
||||
|
||||
#define XP_CONNECTIONLESS 0x00000001
|
||||
#define XP_GUARANTEED_DELIVERY 0x00000002
|
||||
@ -420,7 +419,7 @@ int WSAAPI closesocket(SOCKET sockfd)
|
||||
|
||||
if(sock->flags & IPX_BOUND)
|
||||
{
|
||||
addr_table_remove(sock);
|
||||
CloseHandle(sock->sock_mut);
|
||||
}
|
||||
|
||||
HASH_DEL(sockets, sock);
|
||||
@ -431,7 +430,59 @@ int WSAAPI closesocket(SOCKET sockfd)
|
||||
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
|
||||
* 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");
|
||||
|
||||
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);
|
||||
addr32_out(sock->addr.sa_netnum, iface->ipx_net);
|
||||
addr48_out(sock->addr.sa_nodenum, iface->ipx_node);
|
||||
sock->addr.sa_socket = addr->sa_socket;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -523,38 +560,30 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen)
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_table_lock();
|
||||
|
||||
/* Resolve any wildcards in the requested address. */
|
||||
|
||||
if(!_complete_bind_address(&ipxaddr))
|
||||
if(!_resolve_bind_address(sock, &ipxaddr))
|
||||
{
|
||||
addr_table_unlock();
|
||||
unlock_sockets();
|
||||
|
||||
WSASetLastError(WSAEADDRNOTAVAIL);
|
||||
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. */
|
||||
|
||||
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();
|
||||
|
||||
WSASetLastError(WSAEADDRINUSE);
|
||||
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. */
|
||||
|
||||
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()));
|
||||
|
||||
addr_table_unlock();
|
||||
CloseHandle(sock->sock_mut);
|
||||
sock->flags &= ~IPX_BOUND;
|
||||
|
||||
unlock_sockets();
|
||||
|
||||
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_WARNING, "Socket %d is NOW INCONSISTENT!", fd);
|
||||
|
||||
addr_table_unlock();
|
||||
CloseHandle(sock->sock_mut);
|
||||
sock->flags &= ~IPX_BOUND;
|
||||
|
||||
unlock_sockets();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
sock->port = bind_addr.sin_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();
|
||||
|
||||
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. */
|
||||
|
||||
addr_table_lock();
|
||||
|
||||
if((sock->addr.sa_socket = addr_table_auto_socket()) != 0)
|
||||
if(!_complete_bind(sock))
|
||||
{
|
||||
sock->flags |= IPX_BOUND;
|
||||
|
||||
addr_table_add(sock);
|
||||
}
|
||||
else{
|
||||
log_printf(LOG_ERROR, "Cannot allocate socket number for SPX socket");
|
||||
log_printf(LOG_WARNING, "Socket %d is NOW INCONSISTENT!", sock->fd);
|
||||
|
||||
addr_table_unlock();
|
||||
unlock_sockets();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_table_unlock();
|
||||
|
||||
{
|
||||
IPX_STRING_ADDR(
|
||||
addr_s,
|
||||
@ -2311,6 +2323,25 @@ SOCKET PASCAL accept(SOCKET s, struct sockaddr *addr, int *addrlen)
|
||||
|
||||
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. */
|
||||
|
||||
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;
|
||||
|
||||
HASH_ADD_INT(sockets, fd, nsock);
|
||||
addr_table_add(nsock);
|
||||
|
||||
if(addr)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user