diff options
author | GDR! <gdr@go2.pl> | 2014-11-25 23:09:45 +0100 |
---|---|---|
committer | GDR! <gdr@go2.pl> | 2014-11-25 23:09:45 +0100 |
commit | 16add85eb81629b07dd7bdb04fbe30be1410cc83 (patch) | |
tree | f2cc52d65a2deb0e8c1014f28d9926612c7cf074 /client.c | |
parent | c311fb3bdd2c26c347c2dd734f97003ac0538037 (diff) |
Multi-connection support client-side.
Dealing with congestion control, too
Diffstat (limited to 'client.c')
-rw-r--r-- | client.c | 221 |
1 files changed, 140 insertions, 81 deletions
@@ -10,6 +10,9 @@ struct timespec ping_sent_time; | |||
10 | /* Client mode tunnel */ | 10 | /* Client mode tunnel */ |
11 | tunnel client_tunnel; | 11 | tunnel client_tunnel; |
12 | 12 | ||
13 | /* Sock representing the local port - call accept() on it */ | ||
14 | int bind_sockfd; | ||
15 | |||
13 | fd_set client_master_fdset; | 16 | fd_set client_master_fdset; |
14 | 17 | ||
15 | int handle_pong_frame(protocol_frame *rcvd_frame) | 18 | int 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 | ||
34 | int local_bind(tunnel *tun) | 37 | int 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 */ | ||
98 | int handle_acktunnel_frame(protocol_frame *rcvd_frame) | 87 | int 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 */ |
127 | int handle_server_tcp_frame(protocol_frame *rcvd_frame) | 122 | int 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 | ||