diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 599 |
1 files changed, 540 insertions, 59 deletions
@@ -1,16 +1,3 @@ | |||
1 | #include <arpa/inet.h> | ||
2 | #include <errno.h> | ||
3 | #include <netdb.h> | ||
4 | #include <netinet/in.h> | ||
5 | #include <stdio.h> | ||
6 | #include <stdlib.h> | ||
7 | #include <string.h> | ||
8 | #include <sys/socket.h> | ||
9 | #include <sys/time.h> | ||
10 | #include <sys/types.h> | ||
11 | #include <tox/tox.h> | ||
12 | #include <unistd.h> | ||
13 | |||
14 | #include "main.h" | 1 | #include "main.h" |
15 | #include "tox_bootstrap.h" | 2 | #include "tox_bootstrap.h" |
16 | 3 | ||
@@ -18,6 +5,80 @@ static Tox_Options tox_options; | |||
18 | static Tox *tox; | 5 | static Tox *tox; |
19 | int client_socket = 0; | 6 | int client_socket = 0; |
20 | 7 | ||
8 | /** CONFIGURATION OPTIONS **/ | ||
9 | /* Whether we're a client */ | ||
10 | int client_mode = 0; | ||
11 | /* Just send a ping and exit */ | ||
12 | int ping_mode = 0; | ||
13 | /* Remote Tox ID in client mode */ | ||
14 | char *remote_tox_id = NULL; | ||
15 | /* Ports and hostname for port forwarding */ | ||
16 | int remote_port = 0; | ||
17 | char *remote_host = NULL; | ||
18 | int local_port = 0; | ||
19 | |||
20 | /* The state machine */ | ||
21 | int state = CLIENT_STATE_INITIAL; | ||
22 | |||
23 | /* Used in ping mode */ | ||
24 | struct timespec ping_sent_time; | ||
25 | |||
26 | /* Client mode tunnel */ | ||
27 | tunnel client_tunnel; | ||
28 | |||
29 | /* We keep two hash tables: one indexed by sockfd and another by "connection id" */ | ||
30 | tunnel *by_id = NULL; | ||
31 | tunnel *by_fd = NULL; | ||
32 | |||
33 | /* Generate an unique tunnel ID. To be used in a server. */ | ||
34 | uint16_t get_random_tunnel_id() | ||
35 | { | ||
36 | while(1) | ||
37 | { | ||
38 | int key; | ||
39 | uint16_t tunnel_id; | ||
40 | tunnel *tun; | ||
41 | |||
42 | tunnel_id = (uint16_t)rand(); | ||
43 | key = tunnel_id; | ||
44 | |||
45 | HASH_FIND_INT(by_id, &key, tun); | ||
46 | if(!tun) | ||
47 | { | ||
48 | return tunnel_id; | ||
49 | } | ||
50 | fprintf(stderr, "[i] Found duplicated tunnel ID %d\n", key); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | /* Constructor. Returns NULL on failure. */ | ||
55 | static tunnel *tunnel_create(int sockfd, int connid, uint32_t friendnumber) | ||
56 | { | ||
57 | tunnel *t = NULL; | ||
58 | |||
59 | t = calloc(1, sizeof(tunnel)); | ||
60 | if(!t) | ||
61 | { | ||
62 | return NULL; | ||
63 | } | ||
64 | |||
65 | t->sockfd = sockfd; | ||
66 | t->connid = connid; | ||
67 | t->friendnumber = friendnumber; | ||
68 | |||
69 | HASH_ADD_INT( by_id, connid, t ); | ||
70 | HASH_ADD_INT( by_fd, sockfd, t ); | ||
71 | |||
72 | return t; | ||
73 | } | ||
74 | |||
75 | static void tunnel_delete(tunnel *t) | ||
76 | { | ||
77 | HASH_DEL( by_id, t ); | ||
78 | HASH_DEL( by_fd, t ); | ||
79 | free(t); | ||
80 | } | ||
81 | |||
21 | static void writechecksum(uint8_t *address) | 82 | static void writechecksum(uint8_t *address) |
22 | { | 83 | { |
23 | uint8_t *checksum = address + 36; | 84 | uint8_t *checksum = address + 36; |
@@ -30,7 +91,8 @@ static void writechecksum(uint8_t *address) | |||
30 | /* From utox/util.c */ | 91 | /* From utox/util.c */ |
31 | static void to_hex(char_t *a, const char_t *p, int size) | 92 | static void to_hex(char_t *a, const char_t *p, int size) |
32 | { | 93 | { |
33 | char_t b, c, *end = p + size; | 94 | char_t b, c; |
95 | const char_t *end = p + size; | ||
34 | 96 | ||
35 | while(p != end) { | 97 | while(p != end) { |
36 | b = *p++; | 98 | b = *p++; |
@@ -58,6 +120,42 @@ void id_to_string(char_t *dest, const char_t *src) | |||
58 | to_hex(dest, src, TOX_FRIEND_ADDRESS_SIZE); | 120 | to_hex(dest, src, TOX_FRIEND_ADDRESS_SIZE); |
59 | } | 121 | } |
60 | 122 | ||
123 | /* From utox/util.c */ | ||
124 | int 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 | |||
61 | /* bootstrap to dht with bootstrap_nodes */ | 159 | /* bootstrap to dht with bootstrap_nodes */ |
62 | /* From uTox/tox.c */ | 160 | /* From uTox/tox.c */ |
63 | static void do_bootstrap(Tox *tox) | 161 | static void do_bootstrap(Tox *tox) |
@@ -107,28 +205,6 @@ void set_tox_username(Tox *tox) | |||
107 | 205 | ||
108 | // freeaddrinfo(info); | 206 | // freeaddrinfo(info); |
109 | } | 207 | } |
110 | |||
111 | void accept_friend_request(Tox *tox, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata) | ||
112 | { | ||
113 | unsigned char tox_printable_id[TOX_FRIEND_ADDRESS_SIZE * 2 + 1]; | ||
114 | |||
115 | printf("Got friend request\n"); | ||
116 | tox_add_friend_norequest(tox, public_key); | ||
117 | id_to_string(tox_printable_id, public_key); | ||
118 | printf("Accepted friend request from %s\n", tox_printable_id); | ||
119 | } | ||
120 | |||
121 | void cleanup(int status, void *tmp) | ||
122 | { | ||
123 | printf("kthxbye\n"); | ||
124 | fflush(stdout); | ||
125 | tox_kill(tox); | ||
126 | if(client_socket) | ||
127 | { | ||
128 | close(client_socket); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | // get sockaddr, IPv4 or IPv6: | 208 | // get sockaddr, IPv4 or IPv6: |
133 | /* From Beej */ | 209 | /* From Beej */ |
134 | void *get_in_addr(struct sockaddr *sa) | 210 | void *get_in_addr(struct sockaddr *sa) |
@@ -141,15 +217,13 @@ void *get_in_addr(struct sockaddr *sa) | |||
141 | } | 217 | } |
142 | 218 | ||
143 | /* From Beej */ | 219 | /* From Beej */ |
144 | int get_client_socket() | 220 | int get_client_socket(char *hostname, int port) |
145 | { | 221 | { |
146 | int sockfd, numbytes; | 222 | int sockfd, numbytes; |
147 | char buf[READ_BUFFER_SIZE]; | 223 | char buf[READ_BUFFER_SIZE]; |
148 | struct addrinfo hints, *servinfo, *p; | 224 | struct addrinfo hints, *servinfo, *p; |
149 | int rv; | 225 | int rv; |
150 | char s[INET6_ADDRSTRLEN]; | 226 | char s[INET6_ADDRSTRLEN]; |
151 | int port = 22; | ||
152 | char hostname[4096] = "127.0.0.1"; | ||
153 | char port_str[6]; | 227 | char port_str[6]; |
154 | 228 | ||
155 | snprintf(port_str, 6, "%d", port); | 229 | snprintf(port_str, 6, "%d", port); |
@@ -160,7 +234,7 @@ int get_client_socket() | |||
160 | 234 | ||
161 | if ((rv = getaddrinfo(hostname, port_str, &hints, &servinfo)) != 0) { | 235 | if ((rv = getaddrinfo(hostname, port_str, &hints, &servinfo)) != 0) { |
162 | fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); | 236 | fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); |
163 | exit(1); | 237 | return -1; |
164 | } | 238 | } |
165 | 239 | ||
166 | // loop through all the results and connect to the first we can | 240 | // loop through all the results and connect to the first we can |
@@ -196,20 +270,275 @@ int get_client_socket() | |||
196 | return sockfd; | 270 | return sockfd; |
197 | } | 271 | } |
198 | 272 | ||
199 | unsigned int create_packet(unsigned char *dst, unsigned char *data, int data_len, int sockfd) | 273 | /* Proto - our protocol handling */ |
274 | |||
275 | /* | ||
276 | * send_frame: (almost) zero-copy. Overwrites first PROTOCOL_BUFFER_OFFSET bytes of data | ||
277 | * so actual data should start at position PROTOCOL_BUFFER_OFFSET | ||
278 | */ | ||
279 | int send_frame(protocol_frame *frame, uint8_t *data) | ||
280 | { | ||
281 | int rv; | ||
282 | |||
283 | data[0] = PROTOCOL_MAGIC_HIGH; | ||
284 | data[1] = PROTOCOL_MAGIC_LOW; | ||
285 | data[2] = BYTE2(frame->packet_type); | ||
286 | data[3] = BYTE1(frame->packet_type); | ||
287 | data[4] = BYTE2(frame->connid); | ||
288 | data[5] = BYTE1(frame->connid); | ||
289 | data[6] = BYTE2(frame->data_length); | ||
290 | data[7] = BYTE1(frame->data_length); | ||
291 | |||
292 | rv = tox_send_lossless_packet( | ||
293 | tox, | ||
294 | frame->friendnumber, | ||
295 | data, | ||
296 | frame->data_length + PROTOCOL_BUFFER_OFFSET | ||
297 | ); | ||
298 | |||
299 | if(rv < 0) | ||
300 | { | ||
301 | fprintf(stderr, "Failed to send packet to friend %d\n", frame->friendnumber); | ||
302 | } | ||
303 | |||
304 | return rv; | ||
305 | } | ||
306 | |||
307 | int handle_ping_frame(protocol_frame *rcvd_frame) | ||
200 | { | 308 | { |
201 | // assert data_len < 65536 | 309 | uint8_t data[TOX_MAX_CUSTOM_PACKET_SIZE]; |
202 | dst[0] = 0xa2; | 310 | protocol_frame frame_s; |
203 | dst[1] = 0x6a; | 311 | protocol_frame *frame = &frame_s; |
204 | dst[2] = sockfd >> 8; | 312 | |
205 | dst[3] = sockfd & 0xff; | 313 | frame->data = data + PROTOCOL_BUFFER_OFFSET; |
206 | dst[4] = (data_len >> 8) & 0xff; | 314 | memcpy(frame->data, rcvd_frame->data, rcvd_frame->data_length); |
207 | dst[5] = data_len & 0xff; | 315 | |
208 | memcpy(dst+PROTOCOL_BUFFER_OFFSET, data, data_len); | 316 | frame->friendnumber = rcvd_frame->friendnumber; |
209 | return data_len + PROTOCOL_BUFFER_OFFSET; | 317 | frame->packet_type = PACKET_TYPE_PONG; |
318 | frame->data_length = rcvd_frame->data_length; | ||
319 | |||
320 | send_frame(frame, data); | ||
210 | } | 321 | } |
211 | 322 | ||
212 | int do_loop() | 323 | int 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 | |||
342 | int handle_request_tunnel_frame(protocol_frame *rcvd_frame) | ||
343 | { | ||
344 | char *hostname = NULL; | ||
345 | tunnel *tun; | ||
346 | int port = -1; | ||
347 | int sockfd = 0; | ||
348 | uint16_t tunnel_id; | ||
349 | |||
350 | if(client_mode) | ||
351 | { | ||
352 | fprintf(stderr, "Got tunnel request frame from friend #%d when in client mode\n", rcvd_frame->friendnumber); | ||
353 | return -1; | ||
354 | } | ||
355 | |||
356 | port = rcvd_frame->connid; | ||
357 | hostname = calloc(1, rcvd_frame->data_length + 1); | ||
358 | if(!hostname) | ||
359 | { | ||
360 | fprintf(stderr, "Could not allocate memory for tunnel request hostname\n"); | ||
361 | return -1; | ||
362 | } | ||
363 | |||
364 | strncpy(hostname, rcvd_frame->data, rcvd_frame->data_length); | ||
365 | hostname[rcvd_frame->data_length] = '\0'; | ||
366 | |||
367 | printf("Got a request to forward data from %s:%d\n", hostname, port); | ||
368 | |||
369 | tunnel_id = get_random_tunnel_id(); | ||
370 | printf("Tunnel ID: %d\n", tunnel_id); | ||
371 | /* TODO make connection */ | ||
372 | sockfd = get_client_socket(hostname, port); | ||
373 | if(sockfd > 0) | ||
374 | { | ||
375 | tun = tunnel_create(sockfd, tunnel_id, rcvd_frame->friendnumber); | ||
376 | if(tun) | ||
377 | { | ||
378 | fprintf(stderr, "Created tunnel, yay!\n"); | ||
379 | /* TODO send ack */ | ||
380 | } | ||
381 | else | ||
382 | { | ||
383 | fprintf(stderr, "Couldn't allocate memory for tunnel\n"); | ||
384 | } | ||
385 | } | ||
386 | else | ||
387 | { | ||
388 | fprintf(stderr, "Could not connect to %s:%d\n", hostname, port); | ||
389 | /* TODO send reject */ | ||
390 | } | ||
391 | |||
392 | } | ||
393 | |||
394 | /* This is a dispatcher for our encapsulated protocol */ | ||
395 | int handle_frame(protocol_frame *frame) | ||
396 | { | ||
397 | switch(frame->packet_type) | ||
398 | { | ||
399 | case PACKET_TYPE_PING: | ||
400 | return handle_ping_frame(frame); | ||
401 | break; | ||
402 | case PACKET_TYPE_PONG: | ||
403 | return handle_pong_frame(frame); | ||
404 | break; | ||
405 | case PACKET_TYPE_TCP: | ||
406 | break; | ||
407 | case PACKET_TYPE_REQUESTTUNNEL: | ||
408 | handle_request_tunnel_frame(frame); | ||
409 | break; | ||
410 | default: | ||
411 | fprintf(stderr, "Got unknown packet type 0x%x from friend %d\n", | ||
412 | frame->packet_type, | ||
413 | frame->friendnumber | ||
414 | ); | ||
415 | } | ||
416 | |||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * This is a callback which gets a packet from Tox core. | ||
422 | * It checks for basic inconsistiencies and allocates the | ||
423 | * protocol_frame structure. | ||
424 | */ | ||
425 | int parse_lossless_packet(void *sender_uc, const uint8_t *data, uint32_t len) | ||
426 | { | ||
427 | protocol_frame *frame = NULL; | ||
428 | |||
429 | if(len < PROTOCOL_BUFFER_OFFSET) | ||
430 | { | ||
431 | fprintf(stderr, "Received too short data frame - only %d bytes, at least %d expected\n", len, PROTOCOL_BUFFER_OFFSET); | ||
432 | return -1; | ||
433 | } | ||
434 | |||
435 | if(data[0] != PROTOCOL_MAGIC_HIGH || data[1] != PROTOCOL_MAGIC_LOW) | ||
436 | { | ||
437 | fprintf(stderr, "Received data frame with invalid protocol magic number 0x%x%x\n", data[0], data[1]); | ||
438 | return -1; | ||
439 | } | ||
440 | |||
441 | frame = calloc(1, sizeof(protocol_frame)); | ||
442 | if(!frame) | ||
443 | { | ||
444 | fprintf(stderr, "Could not allocate memory for protocol_frame_t\n"); | ||
445 | return -1; | ||
446 | } | ||
447 | |||
448 | /* TODO check if friendnumber is the same in sender and connid tunnel*/ | ||
449 | frame->magic = INT16_AT(data, 0); | ||
450 | frame->packet_type = INT16_AT(data, 2); | ||
451 | frame->connid = INT16_AT(data, 4); | ||
452 | frame->data_length = INT16_AT(data, 6); | ||
453 | frame->data = data + PROTOCOL_BUFFER_OFFSET; | ||
454 | frame->friendnumber = *((uint32_t*)sender_uc); | ||
455 | printf("Got protocol frame magic 0x%x type 0x%x from friend %d\n", frame->magic, frame->packet_type, frame->friendnumber); | ||
456 | |||
457 | if(len < frame->data_length + PROTOCOL_BUFFER_OFFSET) | ||
458 | { | ||
459 | fprintf(stderr, "Received frame too small (attempted buffer overflow?): %d bytes, excepted at least %d bytes\n", len, frame->data_length + PROTOCOL_BUFFER_OFFSET); | ||
460 | return -1; | ||
461 | } | ||
462 | |||
463 | if(frame->data_length > (TOX_MAX_CUSTOM_PACKET_SIZE - PROTOCOL_BUFFER_OFFSET)) | ||
464 | { | ||
465 | fprintf(stderr, "Declared data length too big (attempted buffer overflow?): %d bytes, excepted at most %d bytes\n", frame->data_length, (TOX_MAX_CUSTOM_PACKET_SIZE - PROTOCOL_BUFFER_OFFSET)); | ||
466 | return -1; | ||
467 | } | ||
468 | |||
469 | handle_frame(frame); | ||
470 | } | ||
471 | |||
472 | int send_tunnel_request_packet(char *remote_host, int remote_port, int friend_number) | ||
473 | { | ||
474 | int packet_length = 0; | ||
475 | protocol_frame frame_i, *frame; | ||
476 | char *data = NULL; | ||
477 | |||
478 | fprintf(stderr, "Sending packet to friend #%d to forward %s:%d\n", friend_number, remote_host, remote_port); | ||
479 | packet_length = PROTOCOL_BUFFER_OFFSET + strlen(remote_host); | ||
480 | frame = &frame_i; | ||
481 | |||
482 | data = calloc(1, packet_length); | ||
483 | if(!data) | ||
484 | { | ||
485 | fprintf(stderr, "Could not allocate memory for tunnel request packet\n"); | ||
486 | exit(1); | ||
487 | } | ||
488 | strcpy(data+PROTOCOL_BUFFER_OFFSET, remote_host); | ||
489 | |||
490 | frame->friendnumber = friend_number; | ||
491 | frame->packet_type = PACKET_TYPE_REQUESTTUNNEL; | ||
492 | frame->connid = remote_port; | ||
493 | frame->data_length = strlen(remote_host); | ||
494 | |||
495 | send_frame(frame, data); | ||
496 | |||
497 | free(data); | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | /* End proto */ | ||
502 | |||
503 | void accept_friend_request(Tox *tox, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata) | ||
504 | { | ||
505 | unsigned char tox_printable_id[TOX_FRIEND_ADDRESS_SIZE * 2 + 1]; | ||
506 | int32_t friendnumber; | ||
507 | int32_t *friendnumber_ptr = NULL; | ||
508 | |||
509 | printf("Got friend request\n"); | ||
510 | |||
511 | friendnumber = tox_add_friend_norequest(tox, public_key); | ||
512 | |||
513 | id_to_string(tox_printable_id, public_key); | ||
514 | printf("Accepted friend request from %s as %d\n", tox_printable_id, friendnumber); | ||
515 | |||
516 | /* TODO: this is not freed right now, we're leaking 4 bytes per contact (OMG!) */ | ||
517 | friendnumber_ptr = malloc(sizeof(int32_t)); | ||
518 | if(!friendnumber_ptr) | ||
519 | { | ||
520 | fprintf(stderr, "Could not allocate memory for friendnumber_ptr\n"); | ||
521 | return; | ||
522 | } | ||
523 | |||
524 | *friendnumber_ptr = friendnumber; | ||
525 | |||
526 | tox_lossless_packet_registerhandler(tox, friendnumber, (PROTOCOL_MAGIC_V1)>>8, parse_lossless_packet, (void*)friendnumber_ptr); | ||
527 | } | ||
528 | |||
529 | void cleanup(int status, void *tmp) | ||
530 | { | ||
531 | printf("kthxbye\n"); | ||
532 | fflush(stdout); | ||
533 | tox_kill(tox); | ||
534 | if(client_socket) | ||
535 | { | ||
536 | close(client_socket); | ||
537 | } | ||
538 | } | ||
539 | |||
540 | |||
541 | int do_server_loop() | ||
213 | { | 542 | { |
214 | struct timeval tv; | 543 | struct timeval tv; |
215 | fd_set fds; | 544 | fd_set fds; |
@@ -221,7 +550,7 @@ int do_loop() | |||
221 | tv.tv_usec = 20000; | 550 | tv.tv_usec = 20000; |
222 | 551 | ||
223 | FD_ZERO(&fds); | 552 | FD_ZERO(&fds); |
224 | FD_SET(client_socket, &fds); | 553 | // FD_SET(client_socket, &fds); |
225 | 554 | ||
226 | master = fds; | 555 | master = fds; |
227 | 556 | ||
@@ -245,8 +574,6 @@ int do_loop() | |||
245 | { | 574 | { |
246 | unsigned int tox_packet_length = 0; | 575 | unsigned int tox_packet_length = 0; |
247 | read_buf[nbytes] = '\0'; | 576 | read_buf[nbytes] = '\0'; |
248 | tox_packet_length = create_packet(tox_packet_buf, read_buf, nbytes, client_socket); | ||
249 | tox_send_lossless_packet(tox, 0, tox_packet_buf, tox_packet_length); | ||
250 | printf("READ: %s\n", read_buf); | 577 | printf("READ: %s\n", read_buf); |
251 | } | 578 | } |
252 | } | 579 | } |
@@ -255,10 +582,157 @@ int do_loop() | |||
255 | } | 582 | } |
256 | } | 583 | } |
257 | 584 | ||
585 | int 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 | |||
597 | fprintf(stderr, "Connecting to Tox...\n"); | ||
598 | |||
599 | while(1) | ||
600 | { | ||
601 | /* Let tox do its stuff */ | ||
602 | tox_do(tox); | ||
603 | |||
604 | switch(state) | ||
605 | { | ||
606 | /* | ||
607 | * Send friend request | ||
608 | */ | ||
609 | case CLIENT_STATE_INITIAL: | ||
610 | if(tox_isconnected(tox)) | ||
611 | { | ||
612 | state = CLIENT_STATE_CONNECTED; | ||
613 | } | ||
614 | break; | ||
615 | case CLIENT_STATE_CONNECTED: | ||
616 | { | ||
617 | uint8_t data[] = "Hi, fellow tuntox instance!"; | ||
618 | uint16_t length = sizeof(data); | ||
619 | |||
620 | fprintf(stderr, "Connected. Sending friend request.\n"); | ||
621 | |||
622 | friendnumber = tox_add_friend( | ||
623 | tox, | ||
624 | tox_id, | ||
625 | data, | ||
626 | length | ||
627 | ); | ||
628 | |||
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 | } | ||
646 | else | ||
647 | { | ||
648 | } | ||
649 | break; | ||
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 | } | ||
692 | |||
693 | usleep(tox_do_interval(tox) * 1000); | ||
694 | } | ||
695 | } | ||
696 | |||
697 | void help() | ||
698 | { | ||
699 | fprintf(stderr, "tuntox - Forward ports over the Tox protocol\n"); | ||
700 | fprintf(stderr, "USAGE:\n\n"); | ||
701 | 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"); | ||
703 | fprintf(stderr, "-p - ping the server from -i and exit\n"); | ||
704 | } | ||
705 | |||
258 | int main(int argc, char *argv[]) | 706 | int main(int argc, char *argv[]) |
259 | { | 707 | { |
260 | unsigned char tox_id[TOX_FRIEND_ADDRESS_SIZE]; | 708 | unsigned char tox_id[TOX_FRIEND_ADDRESS_SIZE]; |
261 | unsigned char tox_printable_id[TOX_FRIEND_ADDRESS_SIZE * 2 + 1]; | 709 | unsigned char tox_printable_id[TOX_FRIEND_ADDRESS_SIZE * 2 + 1]; |
710 | int oc; | ||
711 | |||
712 | while ((oc = getopt(argc, argv, "L:pi:")) != -1) | ||
713 | { | ||
714 | switch(oc) | ||
715 | { | ||
716 | case 'L': | ||
717 | /* Local port forwarding */ | ||
718 | client_mode = 1; | ||
719 | remote_port = atoi(optarg); | ||
720 | fprintf(stderr, "Forwarding remote port %d\n", remote_port); | ||
721 | break; | ||
722 | case 'p': | ||
723 | /* Ping */ | ||
724 | client_mode = 1; | ||
725 | ping_mode = 1; | ||
726 | break; | ||
727 | case 'i': | ||
728 | remote_tox_id = optarg; | ||
729 | break; | ||
730 | case '?': | ||
731 | default: | ||
732 | help(); | ||
733 | exit(1); | ||
734 | } | ||
735 | } | ||
262 | 736 | ||
263 | on_exit(cleanup, NULL); | 737 | on_exit(cleanup, NULL); |
264 | 738 | ||
@@ -269,8 +743,6 @@ int main(int argc, char *argv[]) | |||
269 | 743 | ||
270 | tox = tox_new(&tox_options); | 744 | tox = tox_new(&tox_options); |
271 | 745 | ||
272 | tox_callback_friend_request(tox, accept_friend_request, NULL); | ||
273 | |||
274 | set_tox_username(tox); | 746 | set_tox_username(tox); |
275 | 747 | ||
276 | tox_get_address(tox, tox_id); | 748 | tox_get_address(tox, tox_id); |
@@ -280,10 +752,19 @@ int main(int argc, char *argv[]) | |||
280 | 752 | ||
281 | do_bootstrap(tox); | 753 | do_bootstrap(tox); |
282 | 754 | ||
283 | /* Connect to the forwarded service */ | 755 | /* TODO use proper argparse */ |
284 | client_socket = get_client_socket(); | 756 | if(client_mode) |
757 | { | ||
758 | do_client_loop(remote_tox_id); | ||
759 | } | ||
760 | else | ||
761 | { | ||
762 | /* Connect to the forwarded service */ | ||
763 | // client_socket = get_client_socket(); | ||
285 | 764 | ||
286 | do_loop(); | 765 | tox_callback_friend_request(tox, accept_friend_request, NULL); |
766 | do_server_loop(); | ||
767 | } | ||
287 | 768 | ||
288 | return 0; | 769 | return 0; |
289 | } | 770 | } |