mirror of
https://github.com/solemnwarning/ipxwrapper
synced 2024-12-30 16:45:37 +01:00
Implemented (virtual) interface address cache and ipx_interface utility functions.
This commit is contained in:
parent
bee68d52b9
commit
57e4f27bb8
226
src/interface.c
226
src/interface.c
@ -18,17 +18,25 @@
|
||||
#include <windows.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <utlist.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "interface.h"
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
|
||||
#define INTERFACE_CACHE_TTL 5
|
||||
|
||||
static CRITICAL_SECTION interface_cache_cs;
|
||||
|
||||
static ipx_interface_t *interface_cache = NULL;
|
||||
static time_t interface_cache_ctime = 0;
|
||||
|
||||
/* Fetch a list of network interfaces available on the system.
|
||||
*
|
||||
* Returns a linked list of IP_ADAPTER_INFO structures, all allocated within a
|
||||
* single memory block beginning at the first node.
|
||||
*/
|
||||
IP_ADAPTER_INFO *get_sys_interfaces(void)
|
||||
IP_ADAPTER_INFO *load_sys_interfaces(void)
|
||||
{
|
||||
IP_ADAPTER_INFO *ifroot = NULL, *ifptr;
|
||||
ULONG bufsize = sizeof(IP_ADAPTER_INFO) * 8;
|
||||
@ -68,12 +76,10 @@ IP_ADAPTER_INFO *get_sys_interfaces(void)
|
||||
return ifroot;
|
||||
}
|
||||
|
||||
/* Get virtual IPX interfaces
|
||||
* Select a single interface by setting ifnum >= 0
|
||||
*/
|
||||
ipx_interface_t *get_interfaces(int ifnum)
|
||||
/* Load a list of virtual IPX interfaces. */
|
||||
ipx_interface_t *load_ipx_interfaces(void)
|
||||
{
|
||||
IP_ADAPTER_INFO *ifroot = get_sys_interfaces(), *ifptr;
|
||||
IP_ADAPTER_INFO *ifroot = load_sys_interfaces(), *ifptr;
|
||||
|
||||
addr48_t primary = get_primary_iface();
|
||||
|
||||
@ -98,7 +104,7 @@ ipx_interface_t *get_interfaces(int ifnum)
|
||||
{
|
||||
log_printf(LOG_ERROR, "Couldn't allocate ipx_interface!");
|
||||
|
||||
free_ipx_interfaces(&nics);
|
||||
free_ipx_interface_list(&nics);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -126,7 +132,7 @@ ipx_interface_t *get_interfaces(int ifnum)
|
||||
log_printf(LOG_ERROR, "Couldn't allocate ipx_interface_ip!");
|
||||
|
||||
free_ipx_interface(iface);
|
||||
free_ipx_interfaces(&nics);
|
||||
free_ipx_interface_list(&nics);
|
||||
|
||||
continue;
|
||||
}
|
||||
@ -169,28 +175,46 @@ ipx_interface_t *get_interfaces(int ifnum)
|
||||
|
||||
free(ifroot);
|
||||
|
||||
/* Delete every entry in the NIC list except the requested one.
|
||||
*
|
||||
* This is done here rather than when building the list as the primary
|
||||
* interface may change the indexes if it isn't the first.
|
||||
*/
|
||||
|
||||
if(ifnum >= 0)
|
||||
return nics;
|
||||
}
|
||||
|
||||
/* Deep copy an ipx_interface structure.
|
||||
* Returns NULL on malloc failure.
|
||||
*/
|
||||
ipx_interface_t *copy_ipx_interface(const ipx_interface_t *src)
|
||||
{
|
||||
ipx_interface_t *dest = malloc(sizeof(ipx_interface_t));
|
||||
if(!dest)
|
||||
{
|
||||
int this_ifnum = 0;
|
||||
ipx_interface_t *iface, *tmp;
|
||||
|
||||
DL_FOREACH_SAFE(nics, iface, tmp)
|
||||
{
|
||||
if(this_ifnum++ != ifnum)
|
||||
{
|
||||
DL_DELETE(nics, iface);
|
||||
free_ipx_interface(iface);
|
||||
}
|
||||
}
|
||||
log_printf(LOG_ERROR, "Cannot allocate ipx_interface!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nics;
|
||||
*dest = *src;
|
||||
|
||||
dest->ipaddr = NULL;
|
||||
dest->prev = NULL;
|
||||
dest->next = NULL;
|
||||
|
||||
ipx_interface_ip_t *ip;
|
||||
|
||||
DL_FOREACH(src->ipaddr, ip)
|
||||
{
|
||||
ipx_interface_ip_t *new_ip = malloc(sizeof(ipx_interface_ip_t));
|
||||
if(!new_ip)
|
||||
{
|
||||
log_printf(LOG_ERROR, "Cannot allocate ipx_interface_ip!");
|
||||
|
||||
free_ipx_interface(dest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*new_ip = *ip;
|
||||
|
||||
DL_APPEND(dest->ipaddr, new_ip);
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Free an ipx_interface structure and any memory allocated within. */
|
||||
@ -207,8 +231,32 @@ void free_ipx_interface(ipx_interface_t *iface)
|
||||
free(iface);
|
||||
}
|
||||
|
||||
/* Deep copy an entire list of ipx_interface structures.
|
||||
* Returns NULL on malloc failure.
|
||||
*/
|
||||
ipx_interface_t *copy_ipx_interface_list(const ipx_interface_t *src)
|
||||
{
|
||||
ipx_interface_t *dest = NULL;
|
||||
|
||||
const ipx_interface_t *s;
|
||||
|
||||
DL_FOREACH(src, s)
|
||||
{
|
||||
ipx_interface_t *d = copy_ipx_interface(s);
|
||||
if(!d)
|
||||
{
|
||||
free_ipx_interface_list(&dest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DL_APPEND(dest, d);
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Free a list of ipx_interface structures */
|
||||
void free_ipx_interfaces(ipx_interface_t **list)
|
||||
void free_ipx_interface_list(ipx_interface_t **list)
|
||||
{
|
||||
ipx_interface_t *iface, *tmp;
|
||||
|
||||
@ -218,3 +266,125 @@ void free_ipx_interfaces(ipx_interface_t **list)
|
||||
free_ipx_interface(iface);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise the IPX interface cache. */
|
||||
void ipx_interfaces_init(void)
|
||||
{
|
||||
interface_cache = NULL;
|
||||
interface_cache_ctime = 0;
|
||||
|
||||
if(!InitializeCriticalSectionAndSpinCount(&interface_cache_cs, 0x80000000))
|
||||
{
|
||||
log_printf(LOG_ERROR, "Failed to initialise critical section: %s", w32_error(GetLastError()));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Release any resources used by the IPX interface cache. */
|
||||
void ipx_interfaces_cleanup(void)
|
||||
{
|
||||
DeleteCriticalSection(&interface_cache_cs);
|
||||
|
||||
free_ipx_interface_list(&interface_cache);
|
||||
}
|
||||
|
||||
/* Check the age of the IPX interface cache and reload it if necessary.
|
||||
* Ensure you hold interface_cache_cs before calling.
|
||||
*/
|
||||
static void renew_interface_cache(void)
|
||||
{
|
||||
if(time(NULL) - interface_cache_ctime > INTERFACE_CACHE_TTL)
|
||||
{
|
||||
free_ipx_interface_list(&interface_cache);
|
||||
|
||||
interface_cache = load_ipx_interfaces();
|
||||
interface_cache_ctime = time(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a copy of the IPX interface cache. The cache will be reloaded before
|
||||
* copying if too old.
|
||||
*/
|
||||
ipx_interface_t *get_ipx_interfaces(void)
|
||||
{
|
||||
EnterCriticalSection(&interface_cache_cs);
|
||||
|
||||
renew_interface_cache();
|
||||
|
||||
ipx_interface_t *copy = copy_ipx_interface_list(interface_cache);
|
||||
|
||||
LeaveCriticalSection(&interface_cache_cs);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/* Search for an IPX interface by address.
|
||||
* Returns NULL if the interface doesn't exist or malloc failure.
|
||||
*/
|
||||
ipx_interface_t *ipx_interface_by_addr(addr32_t net, addr48_t node)
|
||||
{
|
||||
EnterCriticalSection(&interface_cache_cs);
|
||||
|
||||
renew_interface_cache();
|
||||
|
||||
ipx_interface_t *iface;
|
||||
|
||||
DL_FOREACH(interface_cache, iface)
|
||||
{
|
||||
if(iface->ipx_net == net && iface->ipx_node == node)
|
||||
{
|
||||
iface = copy_ipx_interface(iface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&interface_cache_cs);
|
||||
|
||||
return iface;
|
||||
}
|
||||
|
||||
/* Search for an IPX interface by index.
|
||||
* Returns NULL if the interface doesn't exist or malloc failure.
|
||||
*/
|
||||
ipx_interface_t *ipx_interface_by_index(int index)
|
||||
{
|
||||
EnterCriticalSection(&interface_cache_cs);
|
||||
|
||||
renew_interface_cache();
|
||||
|
||||
int iface_index = 0;
|
||||
ipx_interface_t *iface;
|
||||
|
||||
DL_FOREACH(interface_cache, iface)
|
||||
{
|
||||
if(iface_index++ == index)
|
||||
{
|
||||
iface = copy_ipx_interface(iface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&interface_cache_cs);
|
||||
|
||||
return iface;
|
||||
}
|
||||
|
||||
/* Returns the number of IPX interfaces. */
|
||||
int ipx_interface_count(void)
|
||||
{
|
||||
EnterCriticalSection(&interface_cache_cs);
|
||||
|
||||
renew_interface_cache();
|
||||
|
||||
int count = 0;
|
||||
ipx_interface_t *iface;
|
||||
|
||||
DL_FOREACH(interface_cache, iface)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&interface_cache_cs);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -52,12 +52,22 @@ struct ipx_interface {
|
||||
ipx_interface_t *next;
|
||||
};
|
||||
|
||||
IP_ADAPTER_INFO *get_sys_interfaces(void);
|
||||
|
||||
ipx_interface_t *get_interfaces(int ifnum);
|
||||
IP_ADAPTER_INFO *load_sys_interfaces(void);
|
||||
ipx_interface_t *load_ipx_interfaces(void);
|
||||
|
||||
ipx_interface_t *copy_ipx_interface(const ipx_interface_t *src);
|
||||
void free_ipx_interface(ipx_interface_t *iface);
|
||||
void free_ipx_interfaces(ipx_interface_t **list);
|
||||
|
||||
ipx_interface_t *copy_ipx_interface_list(const ipx_interface_t *src);
|
||||
void free_ipx_interface_list(ipx_interface_t **list);
|
||||
|
||||
void ipx_interfaces_init(void);
|
||||
void ipx_interfaces_cleanup(void);
|
||||
|
||||
ipx_interface_t *get_ipx_interfaces(void);
|
||||
ipx_interface_t *ipx_interface_by_addr(addr32_t net, addr48_t node);
|
||||
ipx_interface_t *ipx_interface_by_index(int index);
|
||||
int ipx_interface_count(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -86,6 +86,8 @@ BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res) {
|
||||
|
||||
addr_cache_init();
|
||||
|
||||
ipx_interfaces_init();
|
||||
|
||||
if(!rclient_init(&g_rclient)) {
|
||||
return FALSE;
|
||||
}
|
||||
@ -140,6 +142,8 @@ BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res) {
|
||||
DeleteCriticalSection(&addrs_cs);
|
||||
DeleteCriticalSection(&sockets_cs);
|
||||
|
||||
ipx_interfaces_cleanup();
|
||||
|
||||
addr_cache_cleanup();
|
||||
|
||||
unload_dlls();
|
||||
@ -192,7 +196,7 @@ BOOL ip_is_local(uint32_t ipaddr) {
|
||||
if(local_updated + main_config.iface_ttl < time(NULL)) {
|
||||
/* TODO: Use all local IPs rather than just the ones with associated IPX addresses? */
|
||||
|
||||
struct ipx_interface *ifaces = get_interfaces(-1);
|
||||
struct ipx_interface *ifaces = get_ipx_interfaces();
|
||||
struct ipx_interface *i = ifaces;
|
||||
|
||||
while(i) {
|
||||
@ -215,7 +219,7 @@ BOOL ip_is_local(uint32_t ipaddr) {
|
||||
i = i->next;
|
||||
}
|
||||
|
||||
free_ipx_interfaces(&ifaces);
|
||||
free_ipx_interface_list(&ifaces);
|
||||
|
||||
local_updated = time(NULL);
|
||||
}
|
||||
|
@ -336,7 +336,7 @@ static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock,
|
||||
* PLEASE email me with corrections!
|
||||
*/
|
||||
|
||||
struct ipx_interface *ifaces = get_interfaces(-1), *iface;
|
||||
struct ipx_interface *ifaces = get_ipx_interfaces(), *iface;
|
||||
|
||||
addr32_t sa_netnum = addr32_in(addr->sa_netnum);
|
||||
addr48_t sa_nodenum = addr48_in(addr->sa_nodenum);
|
||||
@ -356,7 +356,7 @@ static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock,
|
||||
if(!iface) {
|
||||
log_printf(LOG_ERROR, "bind failed: no such address");
|
||||
|
||||
free_ipx_interfaces(&ifaces);
|
||||
free_ipx_interface_list(&ifaces);
|
||||
|
||||
WSASetLastError(WSAEADDRNOTAVAIL);
|
||||
return -1;
|
||||
@ -372,7 +372,7 @@ static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock,
|
||||
uint32_t iface_ipaddr = iface->ipaddr->ipaddr;
|
||||
uint32_t iface_netmask = iface->ipaddr->netmask;
|
||||
|
||||
free_ipx_interfaces(&ifaces);
|
||||
free_ipx_interface_list(&ifaces);
|
||||
|
||||
EnterCriticalSection(&(router->crit_sec));
|
||||
|
||||
|
@ -524,7 +524,7 @@ int WSAAPI getsockopt(SOCKET fd, int level, int optname, char FAR *optval, int F
|
||||
|
||||
IPX_ADDRESS_DATA *ipxdata = (IPX_ADDRESS_DATA*)optval;
|
||||
|
||||
struct ipx_interface *nic = get_interfaces(ipxdata->adapternum);
|
||||
struct ipx_interface *nic = ipx_interface_by_index(ipxdata->adapternum);
|
||||
|
||||
if(!nic) {
|
||||
RETURN_WSA(ERROR_NO_DATA, -1);
|
||||
@ -552,16 +552,7 @@ int WSAAPI getsockopt(SOCKET fd, int level, int optname, char FAR *optval, int F
|
||||
if(optname == IPX_MAX_ADAPTER_NUM) {
|
||||
CHECK_OPTLEN(sizeof(int));
|
||||
|
||||
*intval = 0;
|
||||
|
||||
struct ipx_interface *ifaces = get_interfaces(-1), *nic;
|
||||
|
||||
for(nic = ifaces; nic;) {
|
||||
(*intval)++;
|
||||
nic = nic->next;
|
||||
}
|
||||
|
||||
free_ipx_interfaces(&ifaces);
|
||||
*intval = ipx_interface_count();
|
||||
|
||||
RETURN(0);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user