Пример #1
0
/* connect:
 *  Set the target address and send the first connection request.  This
 *  might not get through of course; later we can just repeat the send
 *  statement because the target address is already set.  No need to store
 *  it anywhere.
 */
static int connect (NET_CONN *conn, const char *target)
{
	int id;
	static int next_id = 0;
	struct conn_data_t *data = conn->data;

	/* The id is a compound of the current time (with 1 second 
	 * granularity), and an increasing counter.  The time is needed
	 * because the counter resets when you restart the program, and 
	 * the counter is needed because of the granularity of the time. */

	/* Strictly, this line needs a mutex, but there's nowhere around 
	 * here we can call `MUTEX_CREATE'. */
	id = (next_id++ << 16) + (time(NULL) & 0xffff);

	strcpy (data->connect_string, "connect");
	data->connect_string[8] = (id >> 24) & 0xff;
	data->connect_string[9] = (id >> 16) & 0xff;
	data->connect_string[10] = (id >> 8) & 0xff;
	data->connect_string[11] = id & 0xff;
	
	if (net_assigntarget (data->chan, target)) return 1;
	if (net_send (data->chan, data->connect_string, 12)) return 2;
	data->connect_timestamp = __libnet_timer_func();
	return 0;
}
Пример #2
0
/* net_init:
 *  Initialises the libnet library.
 */
int net_init (void) {
  if (!initialised) {
    initialised = 1;
    
    if (!__libnet_internal__mutex_create)
        net_set_mutex_funcs (NULL, NULL, NULL, NULL);
    if (!__libnet_timer_func)
        net_set_timer_func (NULL);
    __libnet_timer_func();
    
    detected_drivers = net_driverlist_create();
    initialised_drivers = net_driverlist_create();
    temp_detected_list = net_driverlist_create();
    net_drivers_all = net_driverlist_create();

    __libnet_internal__classes_init();
    __libnet_internal__drivers_init();
    __libnet_internal__channels_init();
    __libnet_internal__conns_init();
    
    if (!done_atexit) {
      if (atexit(exitfunc)) {
	exitfunc();
	return 1;
      }
      done_atexit = 1;
    } 
  }
  return 0;
}
Пример #3
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;
}
Пример #4
0
/* poll_connect:
 *  This function does two things.  Firstly it checks for a response from 
 *  the server.  If there's no response, it then resends the connection 
 *  request.
 *
 *  The possible problem here is that the server's response might just be
 *  delayed.  The best way I can see around this problem is for the server
 *  to keep an eye on the return addresses of the connection attempts, and
 *  not open a fresh channel each time a duplicate of an old packet arrives.
 *  This actually kills two birds with one stone, since if either the 
 *  client's request packet or the server's response packet are dropped, the
 *  client will eventually resend, causing the server to send an identical 
 *  response.
 *
 *  Later note:  In fact we needed to introduce an almost-unique identifier
 *  to pass as well, since the channel's address may be reused later on.
 */
static int poll_connect (NET_CONN *conn)
{
	struct conn_data_t *data = conn->data;
	char buffer[8+NET_MAX_ADDRESS_LENGTH];
	char addr[NET_MAX_ADDRESS_LENGTH];
	
	if ((net_receive (data->chan, buffer, 8+NET_MAX_ADDRESS_LENGTH, addr) == 8+NET_MAX_ADDRESS_LENGTH) && (!memcmp (buffer, "\0\0\0\0\0\0\0", 8))) {
		net_fixupaddress_channel(data->chan, &buffer[8], addr);
		net_assigntarget (data->chan, addr);
		strcpy (conn->peer_addr, addr);
		return 1;
	}
	/* No response */
	{
		unsigned long clock_value = __libnet_timer_func();
		if ((unsigned)(clock_value - data->connect_timestamp) > RESEND_RATE) {
			net_send (data->chan, data->connect_string, 8);
			data->connect_timestamp = clock_value;
		}
	}
	return 0;
}
Пример #5
0
/* poll:
 *  This function handles all the true I/O for the RDMs.
 */
static void poll (NET_CONN *conn)
{
	struct conn_data_t *data = conn->data;
	
	/* First check whether anything in the outgoing queue needs sending */
	{
		struct out_packet_t *outp;
		int clock_value = __libnet_timer_func(), i;
		for (i = 0; i < MAX_OUTGOING_PACKETS; i++) {
			outp = data->out.packets + i;
			if ((outp->data) && (!outp->ack) && ((unsigned)(clock_value - outp->last_send_time) > RESEND_RATE)) {
				net_send (data->chan, outp->data, outp->size + 4);
				outp->last_send_time = clock_value;
			}
		}
	}
	
	/* Then receive any incoming data */
	{
		int count = 10;  /* max num of packets [we're not meant to block] */
		unsigned char receive_buffer[16384];
		
		while (count--) {
			int x;
			unsigned id;
			x = net_receive (data->chan, receive_buffer, sizeof receive_buffer, 0);
			if ((x == 0) || (x == -1)) break; /* quit if no more data or error */
			if (x < 4) continue;    /* badly formed packet -- no ID */
			id = 0;
			id = (id << 8) + receive_buffer[3];
			id = (id << 8) + receive_buffer[2];
			id = (id << 8) + receive_buffer[1];
			id = (id << 8) + receive_buffer[0];
			if (id == 0) {    /* it's an acknowledgement */
				if (x != 8) continue;   /* badly formed */
				id = (id << 8) + receive_buffer[7];
				id = (id << 8) + receive_buffer[6];
				id = (id << 8) + receive_buffer[5];
				id = (id << 8) + receive_buffer[4];
				if (id >= data->out.base_index)
					data->out.packets[id % MAX_OUTGOING_PACKETS].ack = 1;
				if (id == data->out.base_index) {
					int i, j = id % MAX_OUTGOING_PACKETS;
					for (i = 0; i < MAX_OUTGOING_PACKETS; i++) {
						if (!data->out.packets[j].ack || !data->out.packets[j].data) break;
						data->out.base_index++;
						free (data->out.packets[j].data);
						data->out.packets[j].data = NULL;
						j = (j + 1) % MAX_OUTGOING_PACKETS;
					}
				}
				continue;
			}
			
			if (x == 4) continue;          /* zero length */
			
			if (id >= data->in.base_index + MAX_INCOMING_PACKETS)
				continue;

			if (id >= data->in.base_index) {
				struct in_packet_t *ptr = data->in.packets + id % MAX_INCOMING_PACKETS;
				if (!ptr->data) {   /* haven't got this one yet */
					ptr->data = malloc (x - 4);
					if (!ptr->data) continue;
					memcpy (ptr->data, receive_buffer + 4, x - 4);
					ptr->size = x - 4;
				}
			}
			/* Acknowledge */
			{
				char buf[8] = { 0 };
				memcpy (buf + 4, receive_buffer, 4);
				net_send (data->chan, buf, 8);
			}
		}
	}
}
Пример #6
0
/* safe_sleep:
 *  This routine acts roughly like `sleep', waiting a certain 
 *  number of seconds.  It's used because in Linux at least, 
 *  normal `sleep' uses SIGALRM in Linux, which we'd rather 
 *  not touch (Allegro likes it to be left alone).
 */
static void safe_sleep (int seconds)
{
	unsigned x = __libnet_timer_func();
	int y = 0;
	while (y < seconds * 1000) y = (unsigned)(__libnet_timer_func() - x);
}