summaryrefslogtreecommitdiff
path: root/client.c
diff options
context:
space:
mode:
authorGDR! <gdr@go2.pl>2014-11-25 23:09:45 +0100
committerGDR! <gdr@go2.pl>2014-11-25 23:09:45 +0100
commit16add85eb81629b07dd7bdb04fbe30be1410cc83 (patch)
treef2cc52d65a2deb0e8c1014f28d9926612c7cf074 /client.c
parentc311fb3bdd2c26c347c2dd734f97003ac0538037 (diff)
Multi-connection support client-side.
Dealing with congestion control, too
Diffstat (limited to 'client.c')
-rw-r--r--client.c221
1 files changed, 140 insertions, 81 deletions
diff --git a/client.c b/client.c
index 190c7e5..75d4b0d 100644
--- a/client.c
+++ b/client.c
@@ -10,6 +10,9 @@ struct timespec ping_sent_time;
10/* Client mode tunnel */ 10/* Client mode tunnel */
11tunnel client_tunnel; 11tunnel client_tunnel;
12 12
13/* Sock representing the local port - call accept() on it */
14int bind_sockfd;
15
13fd_set client_master_fdset; 16fd_set client_master_fdset;
14 17
15int handle_pong_frame(protocol_frame *rcvd_frame) 18int handle_pong_frame(protocol_frame *rcvd_frame)
@@ -31,17 +34,12 @@ int handle_pong_frame(protocol_frame *rcvd_frame)
31 } 34 }
32} 35}
33 36
34int local_bind(tunnel *tun) 37int local_bind()
35{ 38{
36 struct addrinfo hints, *res; 39 struct addrinfo hints, *res;
37 int sockfd;
38 char port[6]; 40 char port[6];
39 int yes = 1; 41 int yes = 1;
40 42 int flags;
41 /* accept() variables - TODO they should not be there */
42 int newfd;
43 struct sockaddr_storage remoteaddr; // client address
44 socklen_t addrlen;
45 43
46 snprintf(port, 6, "%d", local_port); 44 snprintf(port, 6, "%d", local_port);
47 45
@@ -52,69 +50,66 @@ int local_bind(tunnel *tun)
52 50
53 getaddrinfo(NULL, port, &hints, &res); 51 getaddrinfo(NULL, port, &hints, &res);
54 52
55 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 53 bind_sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
56 if(sockfd < 0) 54 if(bind_sockfd < 0)
57 { 55 {
58 fprintf(stderr, "Could not create a socket for local listening\n"); 56 fprintf(stderr, "Could not create a socket for local listening: %s\n", strerror(errno));
59 exit(1); 57 exit(1);
60 } 58 }
61 59
62 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); 60 setsockopt(bind_sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
63 61
64 if(bind(sockfd, res->ai_addr, res->ai_addrlen) < 0) 62 /* Set O_NONBLOCK to make accept() non-blocking */
63 if (-1 == (flags = fcntl(bind_sockfd, F_GETFL, 0)))
65 { 64 {
66 fprintf(stderr, "Bind to port %d failed: %s", local_port, strerror(errno)); 65 flags = 0;
67 close(sockfd);
68 exit(1);
69 } 66 }
67 fcntl(bind_sockfd, F_SETFL, flags | O_NONBLOCK);
70 68
71 if(listen(sockfd, 1) < 0) 69 if(bind(bind_sockfd, res->ai_addr, res->ai_addrlen) < 0)
72 { 70 {
73 fprintf(stderr, "Listening on port %d failed: %s", local_port, strerror(errno)); 71 fprintf(stderr, "Bind to port %d failed: %s\n", local_port, strerror(errno));
74 close(sockfd); 72 close(bind_sockfd);
75 exit(1); 73 exit(1);
76 } 74 }
77 75
78 // TODO return sockfd 76 if(listen(bind_sockfd, 1) < 0)
79
80 /* TODO: make a proper accept loop and track tunnels, to handle more than 1 connection */
81 addrlen = sizeof(remoteaddr);
82 newfd = accept(sockfd,
83 (struct sockaddr *)&remoteaddr,
84 &addrlen);
85
86 if(newfd < 0)
87 { 77 {
88 fprintf(stderr, "Error when accepting a local connection: %s\n", strerror(errno)); 78 fprintf(stderr, "Listening on port %d failed: %s\n", local_port, strerror(errno));
89 close(sockfd); 79 close(bind_sockfd);
90 exit(0); 80 exit(1);
91 } 81 }
92 82
93// TODO close(sockfd); 83 fprintf(stderr, "Bound to local port %d\n", local_port);
94
95 return newfd;
96} 84}
97 85
86/* Bind the client.sockfd to a tunnel */
98int handle_acktunnel_frame(protocol_frame *rcvd_frame) 87int handle_acktunnel_frame(protocol_frame *rcvd_frame)
99{ 88{
89 tunnel *tun;
90
100 if(!client_mode) 91 if(!client_mode)
101 { 92 {
102 fprintf(stderr, "Got ACK tunnel frame when not in client mode!?\n"); 93 fprintf(stderr, "Got ACK tunnel frame when not in client mode!?\n");
103 return -1; 94 return -1;
104 } 95 }
105 96
106 client_tunnel.connid = rcvd_frame->connid; 97 tun = tunnel_create(
107 client_tunnel.friendnumber = rcvd_frame->friendnumber; 98 client_tunnel.sockfd,
108 // TODO open local port and fill client_tunnel.sockfd 99 rcvd_frame->connid,
109 printf("New tunnel ID: %d\n", client_tunnel.connid); 100 rcvd_frame->friendnumber
101 );
102
103 /* Mark that we can accept() another connection */
104 client_tunnel.sockfd = -1;
105
106 printf("New tunnel ID: %d\n", tun->connid);
110 107
111 if(client_local_port_mode) 108 if(client_local_port_mode)
112 { 109 {
113 client_tunnel.sockfd = local_bind(&client_tunnel); 110 update_select_nfds(tun->sockfd);
114 update_select_nfds(client_tunnel.sockfd); 111 FD_SET(tun->sockfd, &client_master_fdset);
115 FD_SET(client_tunnel.sockfd, &client_master_fdset); 112 fprintf(stderr, "Accepted a new connection on port %d\n", local_port);
116 fprintf(stderr, "Accepting connections on port %d\n", local_port);
117 state = CLIENT_STATE_FORWARDING;
118 } 113 }
119 else 114 else
120 { 115 {
@@ -126,9 +121,17 @@ int handle_acktunnel_frame(protocol_frame *rcvd_frame)
126/* Handle a TCP frame received from server */ 121/* Handle a TCP frame received from server */
127int handle_server_tcp_frame(protocol_frame *rcvd_frame) 122int handle_server_tcp_frame(protocol_frame *rcvd_frame)
128{ 123{
129 /* TODO find tunnel basing on ID */
130 int offset = 0; 124 int offset = 0;
131 tunnel *tun = &client_tunnel; 125 tunnel *tun = NULL;
126 int tun_id = rcvd_frame->connid;
127
128 HASH_FIND_INT(by_id, &tun_id, tun);
129
130 if(!tun)
131 {
132 fprintf(stderr, "Got TCP frame with unknown tunnel ID %d\n", rcvd_frame->connid);
133 return -1;
134 }
132 135
133 while(offset < rcvd_frame->data_length) 136 while(offset < rcvd_frame->data_length)
134 { 137 {
@@ -143,13 +146,27 @@ int handle_server_tcp_frame(protocol_frame *rcvd_frame)
143 146
144 if(sent_bytes < 0) 147 if(sent_bytes < 0)
145 { 148 {
149 char data[PROTOCOL_BUFFER_OFFSET];
150 protocol_frame frame_st, *frame;
151
146 fprintf(stderr, "Could not write to socket %d: %s\n", tun->sockfd, strerror(errno)); 152 fprintf(stderr, "Could not write to socket %d: %s\n", tun->sockfd, strerror(errno));
153
154 frame = &frame_st;
155 memset(frame, 0, sizeof(protocol_frame));
156 frame->friendnumber = tun->friendnumber;
157 frame->packet_type = PACKET_TYPE_TCP_FIN;
158 frame->connid = tun->connid;
159 frame->data_length = 0;
160 send_frame(frame, data);
161 tunnel_delete(tun);
162
147 return -1; 163 return -1;
148 } 164 }
149 165
150 offset += sent_bytes; 166 offset += sent_bytes;
151 } 167 }
152 168
169 printf("Got %d bytes from server - wrote to fd %d\n", rcvd_frame->data_length, tun->sockfd);
153 170
154 return 0; 171 return 0;
155} 172}
@@ -172,6 +189,12 @@ int do_client_loop(char *tox_id_str)
172 exit(1); 189 exit(1);
173 } 190 }
174 191
192 if(!ping_mode) /* TODO handle pipe mode */
193 {
194 local_bind();
195 signal(SIGPIPE, SIG_IGN);
196 }
197
175 fprintf(stderr, "Connecting to Tox...\n"); 198 fprintf(stderr, "Connecting to Tox...\n");
176 199
177 while(1) 200 while(1)
@@ -232,7 +255,7 @@ int do_client_loop(char *tox_id_str)
232 } 255 }
233 else 256 else
234 { 257 {
235 state = CLIENT_STATE_REQUEST_TUNNEL; 258 state = CLIENT_STATE_BIND_PORT;
236 } 259 }
237 break; 260 break;
238 case CLIENT_STATE_SEND_PING: 261 case CLIENT_STATE_SEND_PING:
@@ -256,9 +279,21 @@ int do_client_loop(char *tox_id_str)
256 case CLIENT_STATE_PING_SENT: 279 case CLIENT_STATE_PING_SENT:
257 /* Just sit there and wait for pong */ 280 /* Just sit there and wait for pong */
258 break; 281 break;
282
283 case CLIENT_STATE_BIND_PORT:
284 if(bind_sockfd < 0)
285 {
286 fprintf(stderr, "Shutting down - could not bind to listening port\n");
287 state = CLIENT_STATE_SHUTDOWN;
288 }
289 else
290 {
291 state = CLIENT_STATE_FORWARDING;
292 }
293 break;
259 case CLIENT_STATE_REQUEST_TUNNEL: 294 case CLIENT_STATE_REQUEST_TUNNEL:
260 send_tunnel_request_packet( 295 send_tunnel_request_packet(
261 "127.0.0.1", 296 remote_host,
262 remote_port, 297 remote_port,
263 friendnumber 298 friendnumber
264 ); 299 );
@@ -268,49 +303,73 @@ int do_client_loop(char *tox_id_str)
268 break; 303 break;
269 case CLIENT_STATE_FORWARDING: 304 case CLIENT_STATE_FORWARDING:
270 { 305 {
306 int accept_fd = 0;
307 tunnel *tmp = NULL;
308 tunnel *tun = NULL;
309
271 tv.tv_sec = 0; 310 tv.tv_sec = 0;
272 tv.tv_usec = 20000; 311 tv.tv_usec = 20000;
273 fds = client_master_fdset; 312 fds = client_master_fdset;
274
275 select(select_nfds, &fds, NULL, NULL, &tv);
276 313
277 if(FD_ISSET(client_tunnel.sockfd, &fds)) 314 /* Handle accepting new connections */
315 if(client_tunnel.sockfd <= 0) /* Don't accept if we're already waiting to establish a tunnel */
278 { 316 {
279 int nbytes = recv(client_tunnel.sockfd, 317 accept_fd = accept(bind_sockfd, NULL, NULL);
280 tox_packet_buf + PROTOCOL_BUFFER_OFFSET, 318 if(accept_fd != -1)
281 READ_BUFFER_SIZE, 0);
282
283 /* Check if connection closed */
284 if(nbytes == 0)
285 { 319 {
286 char data[PROTOCOL_BUFFER_OFFSET]; 320 fprintf(stderr, "Accepting a new connection - requesting tunnel...\n");
287 protocol_frame frame_st, *frame; 321
288 322 /* Open a new tunnel for this FD */
289 fprintf(stderr, "Connection closed\n"); 323 client_tunnel.sockfd = accept_fd;
290 324 send_tunnel_request_packet(
291 frame = &frame_st; 325 remote_host,
292 memset(frame, 0, sizeof(protocol_frame)); 326 remote_port,
293 frame->friendnumber = client_tunnel.friendnumber; 327 friendnumber
294 frame->packet_type = PACKET_TYPE_TCP_FIN; 328 );
295 frame->connid = client_tunnel.connid;
296 frame->data_length = 0;
297 send_frame(frame, data);
298
299 state = CLIENT_STATE_SHUTDOWN;
300
301// exit(1); // TODO handle it in a smarter way (accept() again?)
302 } 329 }
303 else 330 }
331
332 /* Handle reading from sockets */
333 select(select_nfds, &fds, NULL, NULL, &tv);
334 HASH_ITER(hh, by_id, tun, tmp)
335 {
336 if(FD_ISSET(tun->sockfd, &fds))
304 { 337 {
305 protocol_frame frame_st, *frame; 338 int nbytes = recv(tun->sockfd,
306 339 tox_packet_buf + PROTOCOL_BUFFER_OFFSET,
307 frame = &frame_st; 340 READ_BUFFER_SIZE, 0);
308 memset(frame, 0, sizeof(protocol_frame)); 341
309 frame->friendnumber = client_tunnel.friendnumber; 342 /* Check if connection closed */
310 frame->packet_type = PACKET_TYPE_TCP; 343 if(nbytes == 0)
311 frame->connid = client_tunnel.connid; 344 {
312 frame->data_length = nbytes; 345 char data[PROTOCOL_BUFFER_OFFSET];
313 send_frame(frame, tox_packet_buf); 346 protocol_frame frame_st, *frame;
347
348 fprintf(stderr, "Connection closed\n");
349
350 frame = &frame_st;
351 memset(frame, 0, sizeof(protocol_frame));
352 frame->friendnumber = tun->friendnumber;
353 frame->packet_type = PACKET_TYPE_TCP_FIN;
354 frame->connid = tun->connid;
355 frame->data_length = 0;
356 send_frame(frame, data);
357 tunnel_delete(tun);
358 }
359 else
360 {
361 protocol_frame frame_st, *frame;
362
363 frame = &frame_st;
364 memset(frame, 0, sizeof(protocol_frame));
365 frame->friendnumber = tun->friendnumber;
366 frame->packet_type = PACKET_TYPE_TCP;
367 frame->connid = tun->connid;
368 frame->data_length = nbytes;
369 send_frame(frame, tox_packet_buf);
370
371 printf("Wrote %d bytes from sock %d to tunnel %d\n", nbytes, tun->sockfd, tun->connid);
372 }
314 } 373 }
315 } 374 }
316 375