summaryrefslogtreecommitdiff
path: root/client.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 /client.c
parent9b523f2b826dea54613f2eac78f754c9772841b6 (diff)
TCP works, yay
Diffstat (limited to 'client.c')
-rw-r--r--client.c328
1 files changed, 328 insertions, 0 deletions
diff --git a/client.c b/client.c
new file mode 100644
index 0000000..190c7e5
--- /dev/null
+++ b/client.c
@@ -0,0 +1,328 @@
1#include "main.h"
2#include "client.h"
3
4/* The state machine */
5int state = CLIENT_STATE_INITIAL;
6
7/* Used in ping mode */
8struct timespec ping_sent_time;
9
10/* Client mode tunnel */
11tunnel client_tunnel;
12
13fd_set client_master_fdset;
14
15int handle_pong_frame(protocol_frame *rcvd_frame)
16{
17 struct timespec pong_rcvd_time;
18 double secs1, secs2;
19
20 clock_gettime(CLOCK_MONOTONIC, &pong_rcvd_time);
21
22 secs1 = (1.0 * ping_sent_time.tv_sec) + (1e-9 * ping_sent_time.tv_nsec);
23 secs2 = (1.0 * pong_rcvd_time.tv_sec) + (1e-9 * pong_rcvd_time.tv_nsec);
24
25 printf("GOT PONG! Time = %.3fs\n", secs2-secs1);
26
27 if(ping_mode)
28 {
29// state = CLIENT_STATE_PONG_RECEIVED;
30 state = CLIENT_STATE_SEND_PING;
31 }
32}
33
34int local_bind(tunnel *tun)
35{
36 struct addrinfo hints, *res;
37 int sockfd;
38 char port[6];
39 int yes = 1;
40
41 /* accept() variables - TODO they should not be there */
42 int newfd;
43 struct sockaddr_storage remoteaddr; // client address
44 socklen_t addrlen;
45
46 snprintf(port, 6, "%d", local_port);
47
48 memset(&hints, 0, sizeof hints);
49 hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
50 hints.ai_socktype = SOCK_STREAM;
51 hints.ai_flags = AI_PASSIVE; // fill in my IP for me
52
53 getaddrinfo(NULL, port, &hints, &res);
54
55 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
56 if(sockfd < 0)
57 {
58 fprintf(stderr, "Could not create a socket for local listening\n");
59 exit(1);
60 }
61
62 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
63
64 if(bind(sockfd, res->ai_addr, res->ai_addrlen) < 0)
65 {
66 fprintf(stderr, "Bind to port %d failed: %s", local_port, strerror(errno));
67 close(sockfd);
68 exit(1);
69 }
70
71 if(listen(sockfd, 1) < 0)
72 {
73 fprintf(stderr, "Listening on port %d failed: %s", local_port, strerror(errno));
74 close(sockfd);
75 exit(1);
76 }
77
78 // TODO return sockfd
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 {
88 fprintf(stderr, "Error when accepting a local connection: %s\n", strerror(errno));
89 close(sockfd);
90 exit(0);
91 }
92
93// TODO close(sockfd);
94
95 return newfd;
96}
97
98int handle_acktunnel_frame(protocol_frame *rcvd_frame)
99{
100 if(!client_mode)
101 {
102 fprintf(stderr, "Got ACK tunnel frame when not in client mode!?\n");
103 return -1;
104 }
105
106 client_tunnel.connid = rcvd_frame->connid;
107 client_tunnel.friendnumber = rcvd_frame->friendnumber;
108 // TODO open local port and fill client_tunnel.sockfd
109 printf("New tunnel ID: %d\n", client_tunnel.connid);
110
111 if(client_local_port_mode)
112 {
113 client_tunnel.sockfd = local_bind(&client_tunnel);
114 update_select_nfds(client_tunnel.sockfd);
115 FD_SET(client_tunnel.sockfd, &client_master_fdset);
116 fprintf(stderr, "Accepting connections on port %d\n", local_port);
117 state = CLIENT_STATE_FORWARDING;
118 }
119 else
120 {
121 fprintf(stderr, "This tunnel mode is not supported yet");
122 exit(1);
123 }
124}
125
126/* Handle a TCP frame received from server */
127int handle_server_tcp_frame(protocol_frame *rcvd_frame)
128{
129 /* TODO find tunnel basing on ID */
130 int offset = 0;
131 tunnel *tun = &client_tunnel;
132
133 while(offset < rcvd_frame->data_length)
134 {
135 int sent_bytes;
136
137 sent_bytes = send(
138 tun->sockfd,
139 rcvd_frame->data + offset,
140 rcvd_frame->data_length - offset,
141 0
142 );
143
144 if(sent_bytes < 0)
145 {
146 fprintf(stderr, "Could not write to socket %d: %s\n", tun->sockfd, strerror(errno));
147 return -1;
148 }
149
150 offset += sent_bytes;
151 }
152
153
154 return 0;
155}
156
157/* Main loop for the client */
158int do_client_loop(char *tox_id_str)
159{
160 unsigned char tox_packet_buf[PROTOCOL_MAX_PACKET_SIZE];
161 unsigned char tox_id[TOX_FRIEND_ADDRESS_SIZE];
162 uint32_t friendnumber;
163 struct timeval tv;
164 fd_set fds;
165
166 client_tunnel.sockfd = 0;
167 FD_ZERO(&client_master_fdset);
168
169 if(!string_to_id(tox_id, tox_id_str))
170 {
171 fprintf(stderr, "Invalid Tox ID");
172 exit(1);
173 }
174
175 fprintf(stderr, "Connecting to Tox...\n");
176
177 while(1)
178 {
179 /* Let tox do its stuff */
180 tox_do(tox);
181
182 switch(state)
183 {
184 /*
185 * Send friend request
186 */
187 case CLIENT_STATE_INITIAL:
188 if(tox_isconnected(tox))
189 {
190 state = CLIENT_STATE_CONNECTED;
191 }
192 break;
193 case CLIENT_STATE_CONNECTED:
194 {
195 uint8_t data[] = "Hi, fellow tuntox instance!";
196 uint16_t length = sizeof(data);
197
198 fprintf(stderr, "Connected. Sending friend request.\n");
199
200 friendnumber = tox_add_friend(
201 tox,
202 tox_id,
203 data,
204 length
205 );
206
207 if(friendnumber < 0)
208 {
209 fprintf(stderr, "Error %d adding friend %s\n", friendnumber, tox_id);
210 exit(-1);
211 }
212
213 tox_lossless_packet_registerhandler(tox, friendnumber, (PROTOCOL_MAGIC_V1)>>8, parse_lossless_packet, (void*)&friendnumber);
214 state = CLIENT_STATE_SENTREQUEST;
215 fprintf(stderr, "Waiting for friend to accept us...\n");
216 }
217 break;
218 case CLIENT_STATE_SENTREQUEST:
219 if(tox_get_friend_connection_status(tox, friendnumber) == 1)
220 {
221 fprintf(stderr, "Friend request accepted!\n");
222 state = CLIENT_STATE_REQUEST_ACCEPTED;
223 }
224 else
225 {
226 }
227 break;
228 case CLIENT_STATE_REQUEST_ACCEPTED:
229 if(ping_mode)
230 {
231 state = CLIENT_STATE_SEND_PING;
232 }
233 else
234 {
235 state = CLIENT_STATE_REQUEST_TUNNEL;
236 }
237 break;
238 case CLIENT_STATE_SEND_PING:
239 /* Send the ping packet */
240 {
241 uint8_t data[] = {
242 0xa2, 0x6a, 0x01, 0x08, 0x00, 0x00, 0x00, 0x05,
243 0x48, 0x65, 0x6c, 0x6c, 0x6f
244 };
245
246 clock_gettime(CLOCK_MONOTONIC, &ping_sent_time);
247 tox_send_lossless_packet(
248 tox,
249 friendnumber,
250 data,
251 sizeof(data)
252 );
253 }
254 state = CLIENT_STATE_PING_SENT;
255 break;
256 case CLIENT_STATE_PING_SENT:
257 /* Just sit there and wait for pong */
258 break;
259 case CLIENT_STATE_REQUEST_TUNNEL:
260 send_tunnel_request_packet(
261 "127.0.0.1",
262 remote_port,
263 friendnumber
264 );
265 state = CLIENT_STATE_WAIT_FOR_ACKTUNNEL;
266 break;
267 case CLIENT_STATE_WAIT_FOR_ACKTUNNEL:
268 break;
269 case CLIENT_STATE_FORWARDING:
270 {
271 tv.tv_sec = 0;
272 tv.tv_usec = 20000;
273 fds = client_master_fdset;
274
275 select(select_nfds, &fds, NULL, NULL, &tv);
276
277 if(FD_ISSET(client_tunnel.sockfd, &fds))
278 {
279 int nbytes = recv(client_tunnel.sockfd,
280 tox_packet_buf + PROTOCOL_BUFFER_OFFSET,
281 READ_BUFFER_SIZE, 0);
282
283 /* Check if connection closed */
284 if(nbytes == 0)
285 {
286 char data[PROTOCOL_BUFFER_OFFSET];
287 protocol_frame frame_st, *frame;
288
289 fprintf(stderr, "Connection closed\n");
290
291 frame = &frame_st;
292 memset(frame, 0, sizeof(protocol_frame));
293 frame->friendnumber = client_tunnel.friendnumber;
294 frame->packet_type = PACKET_TYPE_TCP_FIN;
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 }
303 else
304 {
305 protocol_frame frame_st, *frame;
306
307 frame = &frame_st;
308 memset(frame, 0, sizeof(protocol_frame));
309 frame->friendnumber = client_tunnel.friendnumber;
310 frame->packet_type = PACKET_TYPE_TCP;
311 frame->connid = client_tunnel.connid;
312 frame->data_length = nbytes;
313 send_frame(frame, tox_packet_buf);
314 }
315 }
316
317 fds = client_master_fdset;
318 }
319 break;
320 case CLIENT_STATE_SHUTDOWN:
321 exit(0);
322 break;
323 }
324
325 usleep(tox_do_interval(tox) * 1000);
326 }
327}
328