void init() { char temp[1024], nick[1024], addr[1024], newaddr[NET_MAX_ADDRESS_LENGTH]; NET_DRIVERLIST drv; drv = net_driverlist_create(); net_driverlist_clear (drv); net_driverlist_add (drv, netdriver); if (!net_initdrivers (drv)) { printf("Error initialising driver.\n"); exit (1); } printf ("Enter target address: "); fgets (addr, 1024, stdin); while (strchr(addr,'\n')) *strchr(addr,'\n')=0; printf ("Enter nickname: "); fgets (nick, 10, stdin); while (strchr(nick,'\n')) *strchr(nick,'\n')=0; if (!(chan = net_openchannel (netdriver, NULL))) { printf ("Unable to open channel.\n"); exit (2); } printf ("Connecting to %s...\n", addr); net_assigntarget (chan, addr); sprintf (temp, "%c%s", CHAT_MAGIC, nick); net_send (chan, temp, strlen (temp)); while ((!net_query (chan))/* && !conio_kbhit()*/); if (0/*conio_kbhit()*/) { conio_getch(); printf ("Aborted.\n"); exit (3); } { int x = net_receive (chan, temp, 1024, newaddr); if (x == -1) { printf ("Receive error.\n"); exit (5); } temp[x] = 0; } if (strcmp (temp, "OK")) { printf ("Connection refused.\n"); exit (4); } printf ("Connection accepted, redirecting... "); fflush (stdout); net_assigntarget (chan, newaddr); printf ("done.\n"); }
/* 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 */ net_assigntarget (((struct conn_data_t *)conn->data)->chan, addr); strcpy (buffer2+8, net_getlocaladdress (data->chan)); net_send (((struct conn_data_t *)conn->data)->chan, buffer2, 8+NET_MAX_ADDRESS_LENGTH); } if (x >= 0) { destroy_queues (newconn); free (data); continue; } strcpy (newconn->peer_addr, addr); return 1; } } return 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; }
/* 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; }
int main (int argc, char **argv) { NET_CONN *listen, *conn = NULL; NET_CHANNEL *chan; char remote[NET_MAX_ADDRESS_LENGTH], buf[NET_MAX_ADDRESS_LENGTH]; char *p, c; int server = -1; if (argc > 1) { if (!strcmp (argv[1], "server")) server = 1; else if (!strcmp (argv[1], "client")) server = 0; } if (server == -1) { puts ("Pass `server' or `client' on the command line."); return 1; } net_init(); net_detectdrivers(net_drivers_all); net_initdrivers(net_drivers_all); if (server) { listen = net_openconn(DRIVER, ""); net_listen(listen); while (!conn) conn = net_poll_listen(listen); } else { conn = net_openconn(DRIVER, NULL); if (net_connect_wait_time(conn, ADDRESS, 5) != 0) { printf("Error connecting\n"); return 1; } } chan = net_openchannel(DRIVER, NULL); p = net_getlocaladdress(chan); net_send_rdm(conn, p, strlen(p) + 1); while (!net_query_rdm(conn)) ; net_receive_rdm(conn, remote, sizeof remote); printf ("Address before fixing: %s\n", remote); if (net_fixupaddress_conn(conn, remote, buf) != 0) { printf("Didn't work\n"); return 1; } printf ("Address after fixing: %s\n", buf); printf("assigning target: %s\n", buf); net_assigntarget(chan, buf); do { c = fgetc(stdin); if (c == '1') net_send(chan, "** Channel", 11); else if (c == '2') net_send_rdm(conn, "** Conn", 8); while (net_query(chan)) { net_receive(chan, buf, sizeof buf, NULL); printf("%s\n", buf); } while (net_query_rdm(conn)) { net_receive_rdm(conn, buf, sizeof buf); printf("%s\n", buf); } } while (c != 'q'); return 0; }