summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorGDR! <gdr@go2.pl>2014-11-16 03:54:56 +0100
committerGDR! <gdr@go2.pl>2014-11-16 03:54:56 +0100
commitc311fb3bdd2c26c347c2dd734f97003ac0538037 (patch)
tree09ec99c8722049f77b08db307e8a5388aa7cb029 /main.c
parent9b523f2b826dea54613f2eac78f754c9772841b6 (diff)
TCP works, yay
Diffstat (limited to 'main.c')
-rw-r--r--main.c431
1 files changed, 193 insertions, 238 deletions
diff --git a/main.c b/main.c
index 661f5dd..77ef128 100644
--- a/main.c
+++ b/main.c
@@ -1,8 +1,9 @@
1#include "main.h" 1#include "main.h"
2#include "client.h"
2#include "tox_bootstrap.h" 3#include "tox_bootstrap.h"
3 4
4static Tox_Options tox_options; 5static Tox_Options tox_options;
5static Tox *tox; 6Tox *tox;
6int client_socket = 0; 7int client_socket = 0;
7 8
8/** CONFIGURATION OPTIONS **/ 9/** CONFIGURATION OPTIONS **/
@@ -10,6 +11,10 @@ int client_socket = 0;
10int client_mode = 0; 11int client_mode = 0;
11/* Just send a ping and exit */ 12/* Just send a ping and exit */
12int ping_mode = 0; 13int ping_mode = 0;
14/* Open a local port and forward it */
15int client_local_port_mode = 0;
16/* Forward stdin/stdout to remote machine - SSH ProxyCommand mode */
17int client_pipe_mode = 0;
13/* Remote Tox ID in client mode */ 18/* Remote Tox ID in client mode */
14char *remote_tox_id = NULL; 19char *remote_tox_id = NULL;
15/* Ports and hostname for port forwarding */ 20/* Ports and hostname for port forwarding */
@@ -17,19 +22,15 @@ int remote_port = 0;
17char *remote_host = NULL; 22char *remote_host = NULL;
18int local_port = 0; 23int local_port = 0;
19 24
20/* The state machine */ 25fd_set master_server_fds;
21int state = CLIENT_STATE_INITIAL;
22
23/* Used in ping mode */
24struct timespec ping_sent_time;
25
26/* Client mode tunnel */
27tunnel client_tunnel;
28 26
29/* We keep two hash tables: one indexed by sockfd and another by "connection id" */ 27/* We keep two hash tables: one indexed by sockfd and another by "connection id" */
30tunnel *by_id = NULL; 28tunnel *by_id = NULL;
31tunnel *by_fd = NULL; 29tunnel *by_fd = NULL;
32 30
31/* Highest used fd + 1 for select() */
32int select_nfds = 4;
33
33/* Generate an unique tunnel ID. To be used in a server. */ 34/* Generate an unique tunnel ID. To be used in a server. */
34uint16_t get_random_tunnel_id() 35uint16_t get_random_tunnel_id()
35{ 36{
@@ -51,6 +52,15 @@ uint16_t get_random_tunnel_id()
51 } 52 }
52} 53}
53 54
55void update_select_nfds(int fd)
56{
57 /* TODO maybe replace with a scan every time to make select() more efficient in the long run? */
58 if(fd + 1 > select_nfds)
59 {
60 select_nfds = fd + 1;
61 }
62}
63
54/* Constructor. Returns NULL on failure. */ 64/* Constructor. Returns NULL on failure. */
55static tunnel *tunnel_create(int sockfd, int connid, uint32_t friendnumber) 65static tunnel *tunnel_create(int sockfd, int connid, uint32_t friendnumber)
56{ 66{
@@ -66,96 +76,24 @@ static tunnel *tunnel_create(int sockfd, int connid, uint32_t friendnumber)
66 t->connid = connid; 76 t->connid = connid;
67 t->friendnumber = friendnumber; 77 t->friendnumber = friendnumber;
68 78
79 update_select_nfds(t->sockfd);
80
69 HASH_ADD_INT( by_id, connid, t ); 81 HASH_ADD_INT( by_id, connid, t );
70 HASH_ADD_INT( by_fd, sockfd, t );
71 82
72 return t; 83 return t;
73} 84}
74 85
75static void tunnel_delete(tunnel *t) 86static void tunnel_delete(tunnel *t)
76{ 87{
88 printf("Deleting tunnel #%d\n", t->connid);
89 if(t->sockfd)
90 {
91 close(t->sockfd);
92 }
77 HASH_DEL( by_id, t ); 93 HASH_DEL( by_id, t );
78 HASH_DEL( by_fd, t );
79 free(t); 94 free(t);
80} 95}
81 96
82static void writechecksum(uint8_t *address)
83{
84 uint8_t *checksum = address + 36;
85 uint32_t i;
86
87 for (i = 0; i < 36; ++i)
88 checksum[i % 2] ^= address[i];
89}
90
91/* From utox/util.c */
92static void to_hex(char_t *a, const char_t *p, int size)
93{
94 char_t b, c;
95 const char_t *end = p + size;
96
97 while(p != end) {
98 b = *p++;
99
100 c = (b & 0xF);
101 b = (b >> 4);
102
103 if(b < 10) {
104 *a++ = b + '0';
105 } else {
106 *a++ = b - 10 + 'A';
107 }
108
109 if(c < 10) {
110 *a++ = c + '0';
111 } else {
112 *a++ = c - 10 + 'A';
113 }
114 }
115}
116
117/* From utox/util.c */
118void id_to_string(char_t *dest, const char_t *src)
119{
120 to_hex(dest, src, TOX_FRIEND_ADDRESS_SIZE);
121}
122
123/* From utox/util.c */
124int string_to_id(char_t *w, char_t *a)
125{
126 char_t *end = w + TOX_FRIEND_ADDRESS_SIZE;
127 while(w != end) {
128 char_t c, v;
129
130 c = *a++;
131 if(c >= '0' && c <= '9') {
132 v = (c - '0') << 4;
133 } else if(c >= 'A' && c <= 'F') {
134 v = (c - 'A' + 10) << 4;
135 } else if(c >= 'a' && c <= 'f') {
136 v = (c - 'a' + 10) << 4;
137 } else {
138 return 0;
139 }
140
141 c = *a++;
142 if(c >= '0' && c <= '9') {
143 v |= (c - '0');
144 } else if(c >= 'A' && c <= 'F') {
145 v |= (c - 'A' + 10);
146 } else if(c >= 'a' && c <= 'f') {
147 v |= (c - 'a' + 10);
148 } else {
149 return 0;
150 }
151
152 *w++ = v;
153 }
154
155 return 1;
156}
157
158
159/* bootstrap to dht with bootstrap_nodes */ 97/* bootstrap to dht with bootstrap_nodes */
160/* From uTox/tox.c */ 98/* From uTox/tox.c */
161static void do_bootstrap(Tox *tox) 99static void do_bootstrap(Tox *tox)
@@ -304,6 +242,23 @@ int send_frame(protocol_frame *frame, uint8_t *data)
304 return rv; 242 return rv;
305} 243}
306 244
245int send_tunnel_ack_frame(tunnel *tun)
246{
247 protocol_frame frame_st;
248 protocol_frame *frame;
249 char data[PROTOCOL_BUFFER_OFFSET];
250
251 frame = &frame_st;
252 memset(frame, 0, sizeof(protocol_frame));
253
254 frame->packet_type = PACKET_TYPE_ACKTUNNEL;
255 frame->connid = tun->connid;
256 frame->data_length = 0;
257 frame->friendnumber = tun->friendnumber;
258
259 return send_frame(frame, data);
260}
261
307int handle_ping_frame(protocol_frame *rcvd_frame) 262int handle_ping_frame(protocol_frame *rcvd_frame)
308{ 263{
309 uint8_t data[TOX_MAX_CUSTOM_PACKET_SIZE]; 264 uint8_t data[TOX_MAX_CUSTOM_PACKET_SIZE];
@@ -320,25 +275,6 @@ int handle_ping_frame(protocol_frame *rcvd_frame)
320 send_frame(frame, data); 275 send_frame(frame, data);
321} 276}
322 277
323int handle_pong_frame(protocol_frame *rcvd_frame)
324{
325 struct timespec pong_rcvd_time;
326 double secs1, secs2;
327
328 clock_gettime(CLOCK_MONOTONIC, &pong_rcvd_time);
329
330 secs1 = (1.0 * ping_sent_time.tv_sec) + (1e-9 * ping_sent_time.tv_nsec);
331 secs2 = (1.0 * pong_rcvd_time.tv_sec) + (1e-9 * pong_rcvd_time.tv_nsec);
332
333 printf("GOT PONG! Time = %.3fs\n", secs2-secs1);
334
335 if(ping_mode)
336 {
337// state = CLIENT_STATE_PONG_RECEIVED;
338 state = CLIENT_STATE_SEND_PING;
339 }
340}
341
342int handle_request_tunnel_frame(protocol_frame *rcvd_frame) 278int handle_request_tunnel_frame(protocol_frame *rcvd_frame)
343{ 279{
344 char *hostname = NULL; 280 char *hostname = NULL;
@@ -375,8 +311,10 @@ int handle_request_tunnel_frame(protocol_frame *rcvd_frame)
375 tun = tunnel_create(sockfd, tunnel_id, rcvd_frame->friendnumber); 311 tun = tunnel_create(sockfd, tunnel_id, rcvd_frame->friendnumber);
376 if(tun) 312 if(tun)
377 { 313 {
314 FD_SET(sockfd, &master_server_fds);
315 update_select_nfds(sockfd);
378 fprintf(stderr, "Created tunnel, yay!\n"); 316 fprintf(stderr, "Created tunnel, yay!\n");
379 /* TODO send ack */ 317 send_tunnel_ack_frame(tun);
380 } 318 }
381 else 319 else
382 { 320 {
@@ -388,7 +326,73 @@ int handle_request_tunnel_frame(protocol_frame *rcvd_frame)
388 fprintf(stderr, "Could not connect to %s:%d\n", hostname, port); 326 fprintf(stderr, "Could not connect to %s:%d\n", hostname, port);
389 /* TODO send reject */ 327 /* TODO send reject */
390 } 328 }
329}
330
331/* Handle a TCP frame received from client */
332int handle_client_tcp_frame(protocol_frame *rcvd_frame)
333{
334 tunnel *tun=NULL;
335 int offset = 0;
336 int connid = rcvd_frame->connid;
337
338 HASH_FIND_INT(by_id, &connid, tun);
339
340 if(!tun)
341 {
342 fprintf(stderr, "Got TCP frame with unknown tunnel ID %d\n", rcvd_frame->connid);
343 return -1;
344 }
345
346 while(offset < rcvd_frame->data_length)
347 {
348 int sent_bytes;
349
350 sent_bytes = send(
351 tun->sockfd,
352 rcvd_frame->data + offset,
353 rcvd_frame->data_length - offset,
354 0
355 );
356
357 if(sent_bytes < 0)
358 {
359 fprintf(stderr, "Could not write to socket %d: %s\n", tun->sockfd, strerror(errno));
360 return -1;
361 }
362
363 offset += sent_bytes;
364 }
365
366 return 0;
367}
368
369int handle_server_tcp_fin_frame(protocol_frame *rcvd_frame)
370{
371
372}
391 373
374/* Handle close-tunnel frame received from the client */
375int handle_client_tcp_fin_frame(protocol_frame *rcvd_frame)
376{
377 tunnel *tun=NULL;
378 int offset = 0;
379 int connid = rcvd_frame->connid;
380
381 HASH_FIND_INT(by_id, &connid, tun);
382
383 if(!tun)
384 {
385 fprintf(stderr, "Got TCP FIN frame with unknown tunnel ID %d\n", rcvd_frame->connid);
386 return -1;
387 }
388
389 if(tun->friendnumber != rcvd_frame->friendnumber)
390 {
391 fprintf(stderr, "Friend #%d tried to close tunnel which belongs to #%d\n", rcvd_frame->friendnumber, tun->friendnumber);
392 return -1;
393 }
394
395 tunnel_delete(tun);
392} 396}
393 397
394/* This is a dispatcher for our encapsulated protocol */ 398/* This is a dispatcher for our encapsulated protocol */
@@ -403,10 +407,31 @@ int handle_frame(protocol_frame *frame)
403 return handle_pong_frame(frame); 407 return handle_pong_frame(frame);
404 break; 408 break;
405 case PACKET_TYPE_TCP: 409 case PACKET_TYPE_TCP:
410 if(client_mode)
411 {
412 return handle_server_tcp_frame(frame);
413 }
414 else
415 {
416 return handle_client_tcp_frame(frame);
417 }
406 break; 418 break;
407 case PACKET_TYPE_REQUESTTUNNEL: 419 case PACKET_TYPE_REQUESTTUNNEL:
408 handle_request_tunnel_frame(frame); 420 handle_request_tunnel_frame(frame);
409 break; 421 break;
422 case PACKET_TYPE_ACKTUNNEL:
423 handle_acktunnel_frame(frame);
424 break;
425 case PACKET_TYPE_TCP_FIN:
426 if(client_mode)
427 {
428 return handle_server_tcp_fin_frame(frame);
429 }
430 else
431 {
432 return handle_client_tcp_fin_frame(frame);
433 }
434 break;
410 default: 435 default:
411 fprintf(stderr, "Got unknown packet type 0x%x from friend %d\n", 436 fprintf(stderr, "Got unknown packet type 0x%x from friend %d\n",
412 frame->packet_type, 437 frame->packet_type,
@@ -542,155 +567,67 @@ int do_server_loop()
542{ 567{
543 struct timeval tv; 568 struct timeval tv;
544 fd_set fds; 569 fd_set fds;
545 fd_set master;
546 unsigned char read_buf[READ_BUFFER_SIZE+1];
547 unsigned char tox_packet_buf[PROTOCOL_MAX_PACKET_SIZE]; 570 unsigned char tox_packet_buf[PROTOCOL_MAX_PACKET_SIZE];
571 tunnel *tun = NULL;
572 tunnel *tmp = NULL;
548 573
549 tv.tv_sec = 0; 574 tv.tv_sec = 0;
550 tv.tv_usec = 20000; 575 tv.tv_usec = 20000;
551 576
552 FD_ZERO(&fds); 577 FD_ZERO(&master_server_fds);
553// FD_SET(client_socket, &fds);
554
555 master = fds;
556 578
557 while(1) 579 while(1)
558 { 580 {
559 /* Let tox do its stuff */ 581 /* Let tox do its stuff */
560 tox_do(tox); 582 tox_do(tox);
561 583
562 /* Poll for data from our client connection */ 584 fds = master_server_fds;
563 select(client_socket+1, &fds, NULL, NULL, &tv);
564 if(FD_ISSET(client_socket, &fds))
565 {
566 int nbytes = recv(client_socket, read_buf, READ_BUFFER_SIZE, 0);
567
568 /* Check if connection closed */
569 if(nbytes == 0)
570 {
571 printf("conn closed!\n");
572 }
573 else
574 {
575 unsigned int tox_packet_length = 0;
576 read_buf[nbytes] = '\0';
577 printf("READ: %s\n", read_buf);
578 }
579 }
580
581 fds = master;
582 }
583}
584
585int do_client_loop(char *tox_id_str)
586{
587 unsigned char tox_packet_buf[PROTOCOL_MAX_PACKET_SIZE];
588 unsigned char tox_id[TOX_FRIEND_ADDRESS_SIZE];
589 uint32_t friendnumber;
590
591 if(!string_to_id(tox_id, tox_id_str))
592 {
593 fprintf(stderr, "Invalid Tox ID");
594 exit(1);
595 }
596 585
597 fprintf(stderr, "Connecting to Tox...\n"); 586 /* Poll for data from our client connection */
598 587 select(select_nfds, &fds, NULL, NULL, &tv);
599 while(1) 588 HASH_ITER(hh, by_id, tun, tmp)
600 {
601 /* Let tox do its stuff */
602 tox_do(tox);
603
604 switch(state)
605 { 589 {
606 /* 590 if(FD_ISSET(tun->sockfd, &fds))
607 * Send friend request 591 {
608 */ 592 int nbytes = recv(tun->sockfd,
609 case CLIENT_STATE_INITIAL: 593 tox_packet_buf+PROTOCOL_BUFFER_OFFSET,
610 if(tox_isconnected(tox)) 594 READ_BUFFER_SIZE, 0);
595
596 /* Check if connection closed */
597 if(nbytes == 0)
611 { 598 {
612 state = CLIENT_STATE_CONNECTED; 599 char data[PROTOCOL_BUFFER_OFFSET];
613 } 600 protocol_frame frame_st, *frame;
614 break; 601
615 case CLIENT_STATE_CONNECTED: 602 printf("conn closed!\n");
616 { 603
617 uint8_t data[] = "Hi, fellow tuntox instance!"; 604 frame = &frame_st;
618 uint16_t length = sizeof(data); 605 memset(frame, 0, sizeof(protocol_frame));
619 606 frame->friendnumber = tun->friendnumber;
620 fprintf(stderr, "Connected. Sending friend request.\n"); 607 frame->packet_type = PACKET_TYPE_TCP_FIN;
621 608 frame->connid = tun->connid;
622 friendnumber = tox_add_friend( 609 frame->data_length = 0;
623 tox, 610 send_frame(frame, data);
624 tox_id, 611
625 data, 612 tunnel_delete(tun);
626 length 613
627 ); 614 /* TODO remove tunnel? resume connection? */
628 615 continue;
629 if(friendnumber < 0)
630 {
631 fprintf(stderr, "Error %d adding friend %s\n", friendnumber, tox_id);
632 exit(-1);
633 }
634
635 tox_lossless_packet_registerhandler(tox, friendnumber, (PROTOCOL_MAGIC_V1)>>8, parse_lossless_packet, (void*)&friendnumber);
636 state = CLIENT_STATE_SENTREQUEST;
637 fprintf(stderr, "Waiting for friend to accept us...\n");
638 }
639 break;
640 case CLIENT_STATE_SENTREQUEST:
641 if(tox_get_friend_connection_status(tox, friendnumber) == 1)
642 {
643 fprintf(stderr, "Friend request accepted!\n");
644 state = CLIENT_STATE_REQUEST_ACCEPTED;
645 } 616 }
646 else 617 else
647 { 618 {
619 protocol_frame frame_st, *frame;
620
621 frame = &frame_st;
622 memset(frame, 0, sizeof(protocol_frame));
623 frame->friendnumber = tun->friendnumber;
624 frame->packet_type = PACKET_TYPE_TCP;
625 frame->connid = tun->connid;
626 frame->data_length = nbytes;
627 send_frame(frame, tox_packet_buf);
648 } 628 }
649 break; 629 }
650 case CLIENT_STATE_REQUEST_ACCEPTED:
651 if(ping_mode)
652 {
653 state = CLIENT_STATE_SEND_PING;
654 }
655 else
656 {
657 state = CLIENT_STATE_REQUEST_TUNNEL;
658 }
659 break;
660 case CLIENT_STATE_SEND_PING:
661 /* Send the ping packet */
662 {
663 uint8_t data[] = {
664 0xa2, 0x6a, 0x01, 0x08, 0x00, 0x00, 0x00, 0x05,
665 0x48, 0x65, 0x6c, 0x6c, 0x6f
666 };
667
668 clock_gettime(CLOCK_MONOTONIC, &ping_sent_time);
669 tox_send_lossless_packet(
670 tox,
671 friendnumber,
672 data,
673 sizeof(data)
674 );
675 }
676 state = CLIENT_STATE_PING_SENT;
677 break;
678 case CLIENT_STATE_PING_SENT:
679 /* Just sit there and wait for pong */
680 break;
681 case CLIENT_STATE_REQUEST_TUNNEL:
682 send_tunnel_request_packet(
683 "127.0.0.1",
684 remote_port,
685 friendnumber
686 );
687 state = CLIENT_STATE_WAIT_FOR_ACKTUNNEL;
688 break;
689 case CLIENT_STATE_WAIT_FOR_ACKTUNNEL:
690 break;
691 } 630 }
692
693 usleep(tox_do_interval(tox) * 1000);
694 } 631 }
695} 632}
696 633
@@ -700,6 +637,7 @@ void help()
700 fprintf(stderr, "USAGE:\n\n"); 637 fprintf(stderr, "USAGE:\n\n");
701 fprintf(stderr, "-i <toxid> - remote point Tox ID\n"); 638 fprintf(stderr, "-i <toxid> - remote point Tox ID\n");
702 fprintf(stderr, "-L <localport>:<remotehostname>:<remoteport> - forward <remotehostname>:<remoteport> to 127.0.0.1:<localport>\n"); 639 fprintf(stderr, "-L <localport>:<remotehostname>:<remoteport> - forward <remotehostname>:<remoteport> to 127.0.0.1:<localport>\n");
640 fprintf(stderr, "-P <remotehostname>:<remoteport> - forward <remotehostname>:<remoteport> to stdin/stdout (SSH ProxyCommand mode)\n");
703 fprintf(stderr, "-p - ping the server from -i and exit\n"); 641 fprintf(stderr, "-p - ping the server from -i and exit\n");
704} 642}
705 643
@@ -716,6 +654,18 @@ int main(int argc, char *argv[])
716 case 'L': 654 case 'L':
717 /* Local port forwarding */ 655 /* Local port forwarding */
718 client_mode = 1; 656 client_mode = 1;
657 client_local_port_mode = 1;
658 if(parse_local_port_forward(optarg, &local_port, &remote_host, &remote_port) < 0)
659 {
660 fprintf(stderr, "Invalid value for -L option - use something like -L 22:127.0.0.1:22\n");
661 exit(1);
662 }
663 fprintf(stderr, "Forwarding remote port %d to local port %d\n", remote_port, local_port);
664 break;
665 case 'P':
666 /* Pipe forwarding */
667 client_mode = 1;
668 client_pipe_mode = 1;
719 remote_port = atoi(optarg); 669 remote_port = atoi(optarg);
720 fprintf(stderr, "Forwarding remote port %d\n", remote_port); 670 fprintf(stderr, "Forwarding remote port %d\n", remote_port);
721 break; 671 break;
@@ -755,6 +705,11 @@ int main(int argc, char *argv[])
755 /* TODO use proper argparse */ 705 /* TODO use proper argparse */
756 if(client_mode) 706 if(client_mode)
757 { 707 {
708 if(!remote_tox_id)
709 {
710 fprintf(stderr, "Tox id is required in client mode. Use -i 58435984ABCDEF475...\n");
711 exit(1);
712 }
758 do_client_loop(remote_tox_id); 713 do_client_loop(remote_tox_id);
759 } 714 }
760 else 715 else