1
0
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:
Daniel Collins 2012-11-03 01:21:25 +00:00
parent bee68d52b9
commit 57e4f27bb8
5 changed files with 223 additions and 48 deletions

View File

@ -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;
}

View File

@ -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
}

View File

@ -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);
}

View File

@ -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));

View File

@ -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);
}