⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipxsocks.c

📁 Libnet is a cross-platform library aimed at game developers. It has an abstract high level API, whic
💻 C
字号:
/*---------------------------------------------------------------- * ipxsocks.c - Sockets-based IPX driver for libnet *---------------------------------------------------------------- *  libnet is (c) Copyright Chad Catlett and George Foot 1997-1998 * *  Please look in `docs' for details, documentation and *  distribution conditions. */#include "platdefs.h"/* If this platform supports this driver, use it. */#if defined __USE_REAL_IPX_LINUX__ || defined __USE_REAL_IPX_WIN__#include <assert.h>#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#ifdef __USE_REAL_IPX_LINUX__#include <netipx/ipx.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/ioctl.h>#include <unistd.h>#define SOCKET int#define INVALID_SOCKET ((SOCKET)-1)#define SOCKET_ERROR (-1)#define ioctlsocket ioctl#define closesocket close#endif#ifdef __USE_REAL_IPX_WIN__#include <winsock.h>#include <wsipx.h>#define sipx_network sa_netnum#define sipx_node sa_nodenum#define sipx_family sa_family#define sipx_port sa_socket#endif/*---------------------------------------- IPX address types */typedef unsigned char ipx_node[6];typedef unsigned char ipx_net[4];typedef struct {	ipx_node node;	ipx_net net;} ipx_addr;/*---------------------------------------- libnet interface */#include "libnet.h"#include "internal.h"#include "config.h"static SOCKET ipx_socket;static unsigned char ipx_buffer[NET_MAX_PACKET_SIZE + 8];/* General default settings */static int default_socket = 24785;    /* default IPX socket number */static int default_port = 1;static int forceport = 0;             /* should we reuse non-vacant ports? */static ipx_addr local_addr;static int disable_driver = 0;#define MAX_PACKETS  16   /* Max number of packets queueable on a port *//*---------------------------------------- Data structures *//* Internal data for channels */struct channel_data_t {	int port;	char target_port[4];	char source_port[4];	struct sockaddr_ipx target_address;	int address_length;};/* Packet */struct packet_t {	int size;	ipx_addr from;	int fromport;	unsigned char data[NET_MAX_PACKET_SIZE];};/* Linked list of port packet queues */struct port_queue_t {	int port;	struct port_queue_t *next;	int usage;	struct packet_t packet[MAX_PACKETS];	int first, count;};static struct port_queue_t *port_queues;/*---------------------------------------- Utility functions */static inline void write_32 (unsigned char *p, unsigned int x){	p[0] = x >> 24;	p[1] = x >> 16;	p[2] = x >> 8;	p[3] = x;}static inline int read_32 (unsigned char *p){	return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];}/*---------------------------------------- Port queue control *//* Find the given port's queue struct, or return NULL */static struct port_queue_t *find_port (int id){	struct port_queue_t *port = port_queues;	while (port && port->port != id) port = port->next;	return port;} /* Get the number of a free port (not the default port) */static int find_free_port (void){	static int next_port;	while ((next_port == 0) || (next_port == default_port) || find_port (next_port)) next_port++;	return next_port;}/* Create a queue for the given port, if it doesn't already exist; * if it does exist, return failure if `force' is zero. */static int create_port (int id, int force){	struct port_queue_t *port = find_port (id);	if (port) {		if (!force) return -1;		port->usage++;		return 0;	}	port = malloc (sizeof *port);	port->port = id;	port->usage = 1;	port->first = port->count = 0;	port->next = port_queues;	port_queues = port;	return 0;}/* Free up the given port.  We have a usage count in case more than one * channel is using the same port. */static void free_port (int id){	struct port_queue_t *port = find_port (id), **prev;	if (!port) return;	if (--port->usage) return;	for (prev = &port_queues; *prev && *prev != port; prev = &(*prev)->next);	if (*prev) *prev = port->next;	free (port);}/* Poll the IPX socket and distribute the packets between the ports */static void poll_ipx_socket (void){	fd_set rfds;	struct timeval tv;	int size, port_id;	struct port_queue_t *port;	struct packet_t *pack;	struct sockaddr_ipx from_addr;	int addrsize;		do {			FD_ZERO (&rfds);		FD_SET (ipx_socket, &rfds);		tv.tv_sec = tv.tv_usec = 0;				if (!select (ipx_socket+1, &rfds, NULL, NULL, &tv)) break;		addrsize = sizeof from_addr;				size = recvfrom (ipx_socket, ipx_buffer, sizeof ipx_buffer, 0, (struct sockaddr *)&from_addr, &addrsize);		if (size < 0) break;				port_id = read_32 (ipx_buffer);		port = find_port (port_id);		if (!port) continue;		if (port->count == MAX_PACKETS) continue;		pack = port->packet + ((port->first + port->count) % MAX_PACKETS);		pack->fromport = read_32 (ipx_buffer + 4);		memcpy (pack->from.net, &from_addr.sipx_network, 4);		memcpy (pack->from.node, from_addr.sipx_node, 6);		memcpy (pack->data, ipx_buffer + 8, size - 8);		pack->size = size - 8;		port->count++;	} while (1);}/*---------------------------------------- Address utility functions */static void write_address (char *s, ipx_addr *addr, int port){	sprintf (s, "%02X%02X%02X%02X/%02X%02X%02X%02X%02X%02X:%d",		addr->net[0], addr->net[1], addr->net[2], addr->net[3],		addr->node[0], addr->node[1], addr->node[2],		addr->node[3], addr->node[4], addr->node[5],		port);}/* helper to read a pair of hex digits */static int read_hex_pair (const char **s){	static char *digits = "0123456789ABCDEF";	char *p1, *p2;	p1 = strchr (digits, toupper(**s));	if (!p1 || !*p1) return -1;	(*s)++;	p2 = strchr (digits, toupper(**s));	if (!p2 || !*p2) return -1;	(*s)++;	return ((p1 - digits) << 4) + (p2 - digits);}/* read the network portion of an address */static int read_net_addr (const char *s, const char *end, ipx_addr *addr){	int i,j;	if (*s == '*' && end - s == 1) {		memset (addr->net, 0xff, 4);		return 0;	}	if (end - s != 8) return 1;	for (i = 0; i < 4; i++) {		j = read_hex_pair (&s);		if (j == -1) return 1;		addr->net[i] = j;	}	return 0;}/* read the node portion of an address */static int read_node_addr (const char *s, const char *end, ipx_addr *addr){	int i,j;		if (*s == '*' && end - s == 1) {		memset (addr->node, 0xff, 6);		return 0;	}		if (end - s != 12) return 1;	for (i = 0; i < 6; i++) {		j = read_hex_pair (&s);		if (j == -1) return 1;		addr->node[i] = j;	}	return 0;}/* parse one of the following: (net = 8 hex digits, node = 12 hex, port = dec) *    net/node:port, net/node, node:port, node */static int parse_address (const char *s, ipx_addr *addr, int *port){	char *colon = strchr (s, ':');	if (port && colon) *port = atoi (colon+1);	if (!colon) colon = strchr (s, '\0');			if (addr) {		char *slash = strchr (s, '/');		if (slash) {			if (read_net_addr (s, slash, addr)) return 1;			s = slash+1;		} else {			memset (addr->net, 0, 4);		}		if (read_node_addr (s, colon, addr)) return 1;	}	return 0;}/*---------------------------------------- General driver functions */static int detect (void){	if (disable_driver) return NET_DETECT_NO;	{#ifdef __USE_REAL_WSOCK_WIN__		unsigned short wVersionRequested = MAKEWORD (1, 1);		WSADATA wsaData;		int err;		err = WSAStartup (wVersionRequested, &wsaData);		if (err) return NET_DETECT_NO;		WSACleanup();#endif		return NET_DETECT_YES;	}}static int init (void){	int one;	struct sockaddr_ipx addr;	int addrlength;#ifdef __USE_REAL_WSOCK_WIN__	short wVersionRequested = MAKEWORD (1, 1);	WSADATA wsaData;	unsigned int err;	err = WSAStartup (wVersionRequested, &wsaData);	if (err) return 1;#endif	ipx_socket = socket (AF_IPX, SOCK_DGRAM, 0);	if (ipx_socket == INVALID_SOCKET) return 1;	one = 1;	if (ioctlsocket (ipx_socket, FIONBIO, (u_long *)&one)) {		closesocket (ipx_socket);		return 2;	}	addr.sipx_family = AF_IPX;	memcpy (&addr.sipx_network, local_addr.net, 4);	memcpy (addr.sipx_node, local_addr.node, 6);	addr.sipx_port = default_socket;	if (bind (ipx_socket, (struct sockaddr *)&addr, sizeof addr)) {		closesocket (ipx_socket);		return 3;	}	addrlength = sizeof addr;	getsockname (ipx_socket, (struct sockaddr *)&addr, &addrlength);	memcpy (local_addr.net, &addr.sipx_network, 4);	memcpy (local_addr.node, addr.sipx_node, 6);	return 0;}static int drv_exit (void){	closesocket (ipx_socket);#ifdef __USE_REAL_WSOCK_WIN__	WSACleanup();#endif	return 0;}/*---------------------------------------- Channel functions */static int init_channel (NET_CHANNEL *chan, const char *addr){	struct channel_data_t *data;	int f = forceport, port = 0;	ipx_addr address = { { 0 }, { 0 } };	if (addr) {		port = default_port;		switch (*addr) {			case '+': f = 1; addr++; break;			case '-': f = 0; addr++; break;		}		if (*addr) parse_address (addr, &address, &port);	}	data = (struct channel_data_t *) malloc (sizeof (struct channel_data_t));	if (!data) return 1;	chan->data = data;		data->port = port ? port : find_free_port();	if (create_port (data->port, f)) {		free (data);		return 2;	}		write_32 (data->source_port, data->port);	data->target_address.sipx_family = AF_IPX;	data->target_address.sipx_port = default_socket;	data->address_length = sizeof data->target_address;		write_address (chan->local_addr, &local_addr, data->port);	return 0;}static int update_target (NET_CHANNEL *chan){	struct channel_data_t *data = chan->data;	int port;	ipx_addr addr;		if (parse_address (chan->target_addr, &addr, &port)) return 1;	if (!port) port = default_port;	data->target_address.sipx_family = AF_IPX;	memcpy (&data->target_address.sipx_network, &addr.net, 4);	memcpy (&data->target_address.sipx_node, &addr.node, 6);	write_32 (data->target_port, port);	return 0;}static int destroy_channel (NET_CHANNEL *chan){	struct channel_data_t *data = chan->data;	free_port (data->port);	free (data);	return 0;}static int drv_send (NET_CHANNEL *chan, const void *buf, int size){	struct channel_data_t *data = chan->data;	int x;	if (size > NET_MAX_PACKET_SIZE) return 1;	/* Unfortunately we need to copy these packets, to prepend the port 	 * numbers. :( */	memcpy (ipx_buffer, data->target_port, 4);	memcpy (ipx_buffer + 4, data->source_port, 4);	memcpy (ipx_buffer + 8, buf, size);	x = sendto (ipx_socket, ipx_buffer, size+8, 0, (struct sockaddr *)&data->target_address, data->address_length);	return (x == SOCKET_ERROR);}static int drv_recv (NET_CHANNEL *chan, void *buf, int size, char *from){	struct channel_data_t *data = chan->data;	struct port_queue_t *port = find_port (data->port);	struct packet_t *pack;		poll_ipx_socket();		if (port->count) {		pack = &port->packet[port->first];		if (size > pack->size) size = pack->size;		memcpy (buf, pack->data, size);		if (from) write_address (from, &pack->from, pack->fromport);		port->first = (port->first + 1) % MAX_PACKETS;		port->count--;		return size;	}	return -1;}static int query (NET_CHANNEL *chan){	struct channel_data_t *data = chan->data;	struct port_queue_t *port = find_port (data->port);		poll_ipx_socket();		return !!port->count;}static void load_config (NET_DRIVER *drv, FILE *fp){	char *option, *value;		if (!__libnet_internal__seek_section (fp, "ipx")) {			while (!__libnet_internal__get_setting (fp, &option, &value)) {					if (!strcmp (option, "port")) {     				int x = atoi (value);				if (x) default_port = x;			} else if (!strcmp (option, "socket")) {				int x = atoi (value);				if (x) default_socket = x;			} else if (!strcmp (option, "forceport")) {				forceport = atoi (value);        			} else if (!strcmp (option, "address")) {        				parse_address (value, &local_addr, NULL);        			} else if (!strcmp (option, "disable")) {				disable_driver = (atoi (value) || (value[0] == 'y'));			}  		}	}#ifdef __USE_REAL_IPX_LINUX__	if (!__libnet_internal__seek_section (fp, "ipx_linux")) {		while (!__libnet_internal__get_setting (fp, &option, &value)) {			if (!strcmp (option, "disable")) {				disable_driver = (atoi (value) || (value[0] == 'y'));			}		}	}#endif#ifdef __USE_REAL_IPX_WIN__	if (!__libnet_internal__seek_section (fp, "ipx_win")) {		while (!__libnet_internal__get_setting (fp, &option, &value)) {			if (!strcmp (option, "disable")) {				disable_driver = (atoi (value) || (value[0] == 'y'));			}		}	}#endif	if (drv->load_conn_config) drv->load_conn_config (drv, fp, "ipx");}#endif  /* __USE_REAL_IPX_LINUX__ || __USE_REAL_IPX_WIN__ *//* Prepare for dummy drivers */#include <stdio.h>#include <stdlib.h>#include "libnet.h"#include "internal.h"static int dummy_detect (void) { return NET_DETECT_NO; }static void dummy_load_config (NET_DRIVER *drv, FILE *fp) { }#define MAKE_REAL_IPX_DRIVER(drv,name) \	NET_DRIVER drv = { \		name, \		"IPX driver", \		NET_CLASS_IPX, \		\		detect, \		init, \		drv_exit, \		\		NULL, NULL, \		\		init_channel, \		destroy_channel, \		\		update_target, \		drv_send, \		drv_recv, \		query, \		\		NULL, NULL, \		NULL, NULL, NULL, NULL, \		NULL, NULL, NULL, NULL, NULL, \		\		load_config, \		NULL, NULL \	}#define MAKE_DUMMY_IPX_DRIVER(drv,name) \	NET_DRIVER drv = { \		name, "IPX driver", \		NET_CLASS_IPX, \		dummy_detect, \		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \		NULL, NULL, NULL, NULL, NULL, NULL, \		NULL, NULL, NULL, NULL, NULL, \		dummy_load_config, \		NULL, NULL \	}#ifdef __USE_REAL_IPX_LINUX__	MAKE_REAL_IPX_DRIVER  (net_driver_ipx_linux, "IPX in Linux");#else	MAKE_DUMMY_IPX_DRIVER (net_driver_ipx_linux, "IPX in Linux");#endif#ifdef __USE_REAL_IPX_WIN__	MAKE_REAL_IPX_DRIVER  (net_driver_ipx_win, "IPX in Windows");#else	MAKE_DUMMY_IPX_DRIVER (net_driver_ipx_win, "IPX in Windows");#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -