📄 connhelp.c
字号:
/*---------------------------------------------------------------- * connhelp.c -- helper conn functions for drivers to use *---------------------------------------------------------------- * libnet is (c) Copyright Chad Catlett and George Foot 1997-1998 * * Please look in `docs' for details, documentation and * distribution conditions. *//* These functions encapsulate the conn system on top of the channel * system. Drivers can support the channels themselves, and set the * conn function entries in their struct to NULL. Libnet will then * automatically redirect them to point at this driver, which chains * back to the real driver using the normal channel functions. */#include <stdlib.h>#include <string.h>#include <time.h>#include "platdefs.h"#include "libnet.h"#include "internal.h"#include "connhelp.h"#include "config.h"#include "timer.h"/*---------------------------------------- Settings for conn queues */struct conn_config { /* Queue sizes -- these must be powers of two */ int outqueue_size, inqueue_size; /* Time between resends of unacknowledged outgoing packets (ms) */ int resend_rate;};/* Defaults */static struct conn_config conn_config_default = { 16, 16, 500 };/* I'm feeling lazy, so I won't change these properly all through the code */#define CONN_CONFIG (conn->driver->conn_config?conn->driver->conn_config:&conn_config_default)#define MAX_OUTGOING_PACKETS (CONN_CONFIG->outqueue_size)#define MAX_INCOMING_PACKETS (CONN_CONFIG->inqueue_size)#define RESEND_RATE (CONN_CONFIG->resend_rate)/*---------------------------------------- Data structures *//* The type used for index numbers. This must be capable of storing 32-bit * unsigned integers. */typedef unsigned int index_t;/* Outgoing packet */struct out_packet_t { index_t index; int ack; int last_send_time; int size; void *data;};/* Incoming packet */struct in_packet_t { int size; void *data;};/* Outgoing packet queue */struct out_t { struct out_packet_t *packets; index_t base_index; index_t next_index;};/* Incoming packet queue */struct in_t { struct in_packet_t *packets; index_t base_index;};/* Connection list */struct conns_list { struct conns_list *next; NET_CHANNEL *chan; /* channel we created for this client */ char *addr; /* address of connecting client */ int client_conn_id; /* client's quasi-unique ref for this conn */ struct conn_data_t *ref; /* cross-reference to conn_data */ int last_access_time; /* time when we were last used */};/* Internal data */struct conn_data_t { NET_CHANNEL *chan; char connect_string[12]; struct conns_list *conns; struct out_t out; struct in_t in; struct conn_data_t *referer; /* pointer to listening conn refering to us */ int connect_timestamp;};/*---------------------------------------- Driver conn functions *//* create_queues: * This sets up the packet queues for a conn. */static int create_queues (NET_CONN *conn){ struct conn_data_t *data = conn->data; int i; data->in.packets = malloc (MAX_INCOMING_PACKETS * sizeof *data->in.packets); if (!data->in.packets) return 1; for (i = 0; i < MAX_INCOMING_PACKETS; i++) data->in.packets[i].data = NULL; data->in.base_index = 1; data->out.packets = malloc (MAX_OUTGOING_PACKETS * sizeof *data->out.packets); if (!data->out.packets) { free (data->in.packets); return 1; } for (i = 0; i < MAX_OUTGOING_PACKETS; i++) data->out.packets[i].data = NULL; data->out.next_index = data->out.base_index = 1; return 0;}static void destroy_queues (NET_CONN *conn){ struct conn_data_t *data = conn->data; int i; for (i = 0; i < MAX_INCOMING_PACKETS; i++) if (data->in.packets[i].data) free (data->in.packets[i].data); for (i = 0; i < MAX_OUTGOING_PACKETS; i++) if (data->out.packets[i].data) free (data->out.packets[i].data); free (data->in.packets); free (data->out.packets);}/* init_conn: * This just chains to the channel initialiser, basically. */static int init_conn (NET_CONN *conn, const char *addr){ struct conn_data_t *data; conn->peer_addr[0] = '\0'; conn->data = data = malloc (sizeof *data); if (!data) return 1; if (create_queues (conn)) { free (data); return 2; } data->conns = NULL; data->referer = NULL; data->chan = net_openchannel (conn->type, addr); if (!data->chan) { destroy_queues (conn); free (data); return 3; } return 0; /* success */}static void destroy_conns_list (struct conns_list *conns){ struct conns_list *c; while (conns) { c = conns->next; if (conns->ref) conns->ref->referer = NULL; free (conns->addr); free (conns); conns = c; }}static int destroy_conn (NET_CONN *conn){ struct conn_data_t *data = conn->data; if (data->referer) { /* remove us from refering list in listener connection */ struct conns_list *prev = NULL, *list = data->referer->conns; while (list) { if (list->chan == data->chan) { struct conns_list *old = list; if (prev) prev->next = list->next; else data->referer->conns = list->next; list = list->next; free(old->addr); free(old); } else { prev = list; list = list->next; } } } net_closechannel (data->chan); destroy_queues (conn); destroy_conns_list (data->conns); free (data); return 0;}/* listen: * Here we need to set up the stub for the list of connectors. We need * this list because there's a (high) chance that we'll get multiple * copies of the same connection request. The list notes which * addresses have requested connections, and which channel was created * for each, so that we can return the same channel rather than opening * another one. */static int listen (NET_CONN *conn){ struct conn_data_t *data = conn->data; data->conns = malloc (sizeof *data->conns); if (!data->conns) return 1; data->conns->next = NULL; data->conns->addr = NULL; data->conns->chan = NULL; data->conns->client_conn_id = -1; data->conns->ref = NULL; return 0;}/* get_channel: * Scans the list of connections for one matching this connector, and * fills it in if found, returning positive. Otherwise, adds a new entry * to the list, fills it in, and returns negative. On error, returns zero. */static int get_channel (struct conns_list *conns, const char *addr, int conn_id, int type, const char *bind, NET_CHANNEL **chan, struct conn_data_t *condat){#if 0 /* Before we do anything else, time out entries which have been here * too long */ struct conns_list *ptr = conns; while (ptr->next) { if ((unsigned)(__libnet_timer_func() - ptr->last_access_time) > 10000) { struct conns_list *ptr2 = ptr->next; ptr->next = ptr2->next; free (ptr2->addr); free (ptr2); } }#endif while (conns->next) { conns = conns->next; if ((conn_id == conns->client_conn_id) && !strcmp (addr, conns->addr)) { *chan = conns->chan; conns->last_access_time = __libnet_timer_func(); return 1; } } conns->next = malloc (sizeof *conns->next); if (conns->next) { conns->next->next = NULL; conns->next->addr = strdup (addr); conns->next->client_conn_id = conn_id; conns->next->ref = condat; conns->next->last_access_time = __libnet_timer_func(); if (conns->next->addr) { conns->next->chan = net_openchannel (type, bind); if (conns->next->chan) { *chan = conns->next->chan; return -1; } free (conns->next->addr); } free (conns->next); conns->next = NULL; } return 0;}/* poll_listen: * Here we check for an incoming connection, and if there is one we * fill in `newconn' with our data pointer for it and the addresses, * and return nonzero. Otherwise return 0. */static int poll_listen (NET_CONN *conn, NET_CONN *newconn){ struct conn_data_t *data; char buffer[12], buffer2[8+NET_MAX_ADDRESS_LENGTH] = { 0, 0, 0, 0, 0, 0, 0, 0 }; char addr[NET_MAX_ADDRESS_LENGTH]; int x; int count = 32; /* maximum number of packets to process */ while (net_query (((struct conn_data_t *)conn->data)->chan) && count-- > 0) { if ((net_receive (((struct conn_data_t *)conn->data)->chan, buffer, 12, addr) == 12) && !memcmp (buffer, "connect", 8)) { newconn->data = data = malloc (sizeof *data); if (!data) continue; if (create_queues (newconn)) { free (data); continue; } data->conns = NULL; x = get_channel ( ((struct conn_data_t *)conn->data)->conns, addr, (buffer[8] << 24) + (buffer[9] << 16) + (buffer[10] << 8) + buffer[11], conn->type, NULL, &data->chan, data ); if (x) { data->referer = conn->data; /* tell new channel where to send in future */ net_assigntarget (data->chan, addr); /* send reply now with address of new channel, through * listening conn so it can get through NATs */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -