diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-01-07 21:45:43 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-01-07 21:45:43 +0000 |
commit | 0f617a81c282e9897b8695612e57ca6cc70f60b7 (patch) | |
tree | 88f675e02789c5d8c9b08bd4b3982a28f20abd18 /src/vpn/vpn_api.c | |
parent | 63170c18741d127640a62148a0788a99c097a652 (diff) | |
download | gnunet-0f617a81c282e9897b8695612e57ca6cc70f60b7.tar.gz gnunet-0f617a81c282e9897b8695612e57ca6cc70f60b7.zip |
-finishing first implementation of VPN client library
Diffstat (limited to 'src/vpn/vpn_api.c')
-rw-r--r-- | src/vpn/vpn_api.c | 343 |
1 files changed, 336 insertions, 7 deletions
diff --git a/src/vpn/vpn_api.c b/src/vpn/vpn_api.c index b6fab37bf..f7759a3bc 100644 --- a/src/vpn/vpn_api.c +++ b/src/vpn/vpn_api.c | |||
@@ -44,6 +44,11 @@ struct GNUNET_VPN_Handle | |||
44 | struct GNUNET_CLIENT_Connection *client; | 44 | struct GNUNET_CLIENT_Connection *client; |
45 | 45 | ||
46 | /** | 46 | /** |
47 | * Active transmission request. | ||
48 | */ | ||
49 | struct GNUNET_CLIENT_TransmitHandle *th; | ||
50 | |||
51 | /** | ||
47 | * Head of list of active redirection requests. | 52 | * Head of list of active redirection requests. |
48 | */ | 53 | */ |
49 | struct GNUNET_VPN_RedirectionRequest *rr_head; | 54 | struct GNUNET_VPN_RedirectionRequest *rr_head; |
@@ -52,6 +57,17 @@ struct GNUNET_VPN_Handle | |||
52 | * Tail of list of active redirection requests. | 57 | * Tail of list of active redirection requests. |
53 | */ | 58 | */ |
54 | struct GNUNET_VPN_RedirectionRequest *rr_tail; | 59 | struct GNUNET_VPN_RedirectionRequest *rr_tail; |
60 | |||
61 | /** | ||
62 | * Identifier of a reconnect task. | ||
63 | */ | ||
64 | GNUNET_SCHEDULER_TaskIdentifier rt; | ||
65 | |||
66 | /** | ||
67 | * ID of the last request that was submitted to the service. | ||
68 | */ | ||
69 | uint64_t request_id_gen; | ||
70 | |||
55 | }; | 71 | }; |
56 | 72 | ||
57 | 73 | ||
@@ -107,6 +123,11 @@ struct GNUNET_VPN_RedirectionRequest | |||
107 | struct GNUNET_TIME_Absolute expiration_time; | 123 | struct GNUNET_TIME_Absolute expiration_time; |
108 | 124 | ||
109 | /** | 125 | /** |
126 | * non-zero if this request has been sent to the service. | ||
127 | */ | ||
128 | uint64_t request_id; | ||
129 | |||
130 | /** | ||
110 | * Desired address family for the result. | 131 | * Desired address family for the result. |
111 | */ | 132 | */ |
112 | int result_af; | 133 | int result_af; |
@@ -131,6 +152,255 @@ struct GNUNET_VPN_RedirectionRequest | |||
131 | 152 | ||
132 | 153 | ||
133 | /** | 154 | /** |
155 | * Disconnect from the service (communication error) and reconnect later. | ||
156 | * | ||
157 | * @param vh handle to reconnect. | ||
158 | */ | ||
159 | static void | ||
160 | reconnect (struct GNUNET_VPN_Handle *vh); | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Function called when we receive a message from the VPN service. | ||
165 | * | ||
166 | * @param cls the 'struct GNUNET_VPN_Handle' | ||
167 | * @param msg message received, NULL on timeout or fatal error | ||
168 | */ | ||
169 | static void | ||
170 | receive_response (void *cls, | ||
171 | const struct GNUNET_MessageHeader* msg) | ||
172 | { | ||
173 | struct GNUNET_VPN_Handle *vh = cls; | ||
174 | const struct RedirectToIpResponseMessage *rm; | ||
175 | struct GNUNET_VPN_RedirectionRequest *rr; | ||
176 | size_t msize; | ||
177 | size_t alen; | ||
178 | int af; | ||
179 | |||
180 | if (NULL == msg) | ||
181 | { | ||
182 | reconnect (vh); | ||
183 | return; | ||
184 | } | ||
185 | if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP) || | ||
186 | (sizeof (struct RedirectToIpResponseMessage) > (msize = ntohs (msg->size))) ) | ||
187 | { | ||
188 | GNUNET_break (0); | ||
189 | reconnect (vh); | ||
190 | return; | ||
191 | } | ||
192 | rm = (const struct RedirectToIpResponseMessage *) msg; | ||
193 | af = (int) ntohl (rm->result_af); | ||
194 | switch (af) | ||
195 | { | ||
196 | case AF_UNSPEC: | ||
197 | alen = 0; | ||
198 | break; | ||
199 | case AF_INET: | ||
200 | alen = sizeof (struct in_addr); | ||
201 | break; | ||
202 | case AF_INET6: | ||
203 | alen = sizeof (struct in6_addr); | ||
204 | break; | ||
205 | default: | ||
206 | GNUNET_break (0); | ||
207 | reconnect (vh); | ||
208 | return; | ||
209 | } | ||
210 | if ( (msize != alen + sizeof (struct RedirectToIpResponseMessage)) || | ||
211 | (0 == rm->request_id) ) | ||
212 | { | ||
213 | GNUNET_break (0); | ||
214 | reconnect (vh); | ||
215 | return; | ||
216 | } | ||
217 | for (rr = vh->rr_head; NULL != rr; rr = rr->next) | ||
218 | { | ||
219 | if (rr->request_id == rm->request_id) | ||
220 | { | ||
221 | GNUNET_CONTAINER_DLL_remove (vh->rr_head, | ||
222 | vh->rr_tail, | ||
223 | rr); | ||
224 | rr->cb (rr->cb_cls, | ||
225 | af, | ||
226 | (af == AF_UNSPEC) ? NULL : &rm[1]); | ||
227 | GNUNET_free (rr); | ||
228 | break; | ||
229 | } | ||
230 | } | ||
231 | GNUNET_CLIENT_receive (vh->client, | ||
232 | &receive_response, vh, | ||
233 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
234 | } | ||
235 | |||
236 | |||
237 | /** | ||
238 | * We're ready to transmit a request to the VPN service. Do it. | ||
239 | * | ||
240 | * @param cls the 'struct GNUNET_VPN_Handle*' | ||
241 | * @param size number of bytes available in buf | ||
242 | * @param buf where to copy the request | ||
243 | * @return number of bytes copied to 'buf' | ||
244 | */ | ||
245 | static size_t | ||
246 | transmit_request (void *cls, | ||
247 | size_t size, | ||
248 | void *buf) | ||
249 | { | ||
250 | struct GNUNET_VPN_Handle *vh = cls; | ||
251 | struct GNUNET_VPN_RedirectionRequest *rr; | ||
252 | struct RedirectToIpRequestMessage rip; | ||
253 | struct RedirectToServiceRequestMessage rs; | ||
254 | char *cbuf; | ||
255 | size_t alen; | ||
256 | size_t ret; | ||
257 | |||
258 | vh->th = NULL; | ||
259 | /* find a pending request */ | ||
260 | rr = vh->rr_head; | ||
261 | while ( (NULL != rr) && | ||
262 | (0 != rr->request_id) ) | ||
263 | rr = rr->next; | ||
264 | if (NULL == rr) | ||
265 | return 0; | ||
266 | |||
267 | /* if first request, start receive loop */ | ||
268 | if (0 == vh->request_id_gen) | ||
269 | GNUNET_CLIENT_receive (vh->client, | ||
270 | &receive_response, vh, | ||
271 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
272 | if (NULL == rr->addr) | ||
273 | { | ||
274 | ret = sizeof (struct RedirectToServiceRequestMessage); | ||
275 | rs.header.size = htons ((uint16_t) ret); | ||
276 | rs.header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE); | ||
277 | rs.nac = htonl (rr->nac); | ||
278 | rs.expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time); | ||
279 | rs.protocol = htonl (rr->protocol); | ||
280 | rs.result_af = htonl (rr->result_af); | ||
281 | rs.target = rr->peer; | ||
282 | rs.service_descriptor = rr->serv; | ||
283 | rs.request_id = rr->request_id = ++vh->request_id_gen; | ||
284 | memcpy (buf, &rs, sizeof (struct RedirectToServiceRequestMessage)); | ||
285 | } | ||
286 | else | ||
287 | { | ||
288 | switch (rr->addr_af) | ||
289 | { | ||
290 | case AF_INET: | ||
291 | alen = sizeof (struct in_addr); | ||
292 | break; | ||
293 | case AF_INET6: | ||
294 | alen = sizeof (struct in6_addr); | ||
295 | break; | ||
296 | default: | ||
297 | GNUNET_assert (0); | ||
298 | return 0; | ||
299 | } | ||
300 | ret = alen + sizeof (struct RedirectToIpRequestMessage); | ||
301 | rip.header.size = htons ((uint16_t) ret); | ||
302 | rip.header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP); | ||
303 | rip.nac = htonl (rr->nac); | ||
304 | rip.expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time); | ||
305 | rip.result_af = htonl (rr->result_af); | ||
306 | rip.addr_af = htonl (rr->addr_af); | ||
307 | rip.request_id = rr->request_id = ++vh->request_id_gen; | ||
308 | cbuf = buf; | ||
309 | memcpy (cbuf, &rip, sizeof (struct RedirectToIpRequestMessage)); | ||
310 | memcpy (&cbuf[sizeof (struct RedirectToIpRequestMessage)], rr->addr, alen); | ||
311 | } | ||
312 | /* test if there are more pending requests */ | ||
313 | while ( (NULL != rr) && | ||
314 | (0 != rr->request_id) ) | ||
315 | rr = rr->next; | ||
316 | if (NULL != rr) | ||
317 | vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client, | ||
318 | sizeof (struct RedirectToServiceRequestMessage), | ||
319 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
320 | GNUNET_NO, | ||
321 | &transmit_request, | ||
322 | vh); | ||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | |||
327 | /** | ||
328 | * Add a request to our request queue and transmit it. | ||
329 | * | ||
330 | * @param rr request to queue and transmit. | ||
331 | */ | ||
332 | static void | ||
333 | queue_request (struct GNUNET_VPN_RedirectionRequest *rr) | ||
334 | { | ||
335 | struct GNUNET_VPN_Handle *vh; | ||
336 | |||
337 | vh = rr->vh; | ||
338 | GNUNET_CONTAINER_DLL_insert_tail (vh->rr_head, | ||
339 | vh->rr_tail, | ||
340 | rr); | ||
341 | if ( (NULL == vh->th) && | ||
342 | (NULL != vh->client) ) | ||
343 | vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client, | ||
344 | sizeof (struct RedirectToServiceRequestMessage), | ||
345 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
346 | GNUNET_NO, | ||
347 | &transmit_request, | ||
348 | vh); | ||
349 | } | ||
350 | |||
351 | |||
352 | /** | ||
353 | * Connect to the VPN service and start again to transmit our requests. | ||
354 | * | ||
355 | * @param cls the 'struct GNUNET_VPN_Handle *' | ||
356 | * @param tc scheduler context | ||
357 | */ | ||
358 | static void | ||
359 | connect_task (void *cls, | ||
360 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
361 | { | ||
362 | struct GNUNET_VPN_Handle *vh = cls; | ||
363 | |||
364 | vh->client = GNUNET_CLIENT_connect ("vpn", vh->cfg); | ||
365 | GNUNET_assert (NULL != vh->client); | ||
366 | GNUNET_assert (NULL != vh->th); | ||
367 | if (NULL != vh->rr_head) | ||
368 | vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client, | ||
369 | sizeof (struct RedirectToServiceRequestMessage), | ||
370 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
371 | GNUNET_NO, | ||
372 | &transmit_request, | ||
373 | vh); | ||
374 | } | ||
375 | |||
376 | |||
377 | /** | ||
378 | * Disconnect from the service (communication error) and reconnect later. | ||
379 | * | ||
380 | * @param vh handle to reconnect. | ||
381 | */ | ||
382 | static void | ||
383 | reconnect (struct GNUNET_VPN_Handle *vh) | ||
384 | { | ||
385 | struct GNUNET_VPN_RedirectionRequest *rr; | ||
386 | |||
387 | if (NULL != vh->th) | ||
388 | { | ||
389 | GNUNET_CLIENT_notify_transmit_ready_cancel (vh->th); | ||
390 | vh->th = NULL; | ||
391 | } | ||
392 | GNUNET_CLIENT_disconnect (vh->client, GNUNET_NO); | ||
393 | vh->client = NULL; | ||
394 | vh->request_id_gen = 0; | ||
395 | for (rr = vh->rr_head; NULL != rr; rr = rr->next) | ||
396 | rr->request_id = 0; | ||
397 | vh->rt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
398 | &connect_task, | ||
399 | vh); | ||
400 | } | ||
401 | |||
402 | |||
403 | /** | ||
134 | * Cancel redirection request with the service. | 404 | * Cancel redirection request with the service. |
135 | * | 405 | * |
136 | * @param rr request to cancel | 406 | * @param rr request to cancel |
@@ -157,7 +427,8 @@ GNUNET_VPN_cancel_request (struct GNUNET_VPN_RedirectionRequest *rr) | |||
157 | * limitations, the longest inactive mappings will be destroyed. | 427 | * limitations, the longest inactive mappings will be destroyed. |
158 | * | 428 | * |
159 | * @param vh VPN handle | 429 | * @param vh VPN handle |
160 | * @param af address family, AF_INET or AF_INET6 | 430 | * @param result_af desired address family for the returned allocation |
431 | * can also be AF_UNSPEC | ||
161 | * @param protocol protocol, IPPROTO_UDP or IPPROTO_TCP | 432 | * @param protocol protocol, IPPROTO_UDP or IPPROTO_TCP |
162 | * @param peer target peer for the redirection | 433 | * @param peer target peer for the redirection |
163 | * @param serv service descriptor to give to the peer | 434 | * @param serv service descriptor to give to the peer |
@@ -173,8 +444,8 @@ GNUNET_VPN_cancel_request (struct GNUNET_VPN_RedirectionRequest *rr) | |||
173 | * anyway) | 444 | * anyway) |
174 | */ | 445 | */ |
175 | struct GNUNET_VPN_RedirectionRequest * | 446 | struct GNUNET_VPN_RedirectionRequest * |
176 | GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *rh, | 447 | GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *vh, |
177 | int af, | 448 | int result_af, |
178 | uint8_t protocol, | 449 | uint8_t protocol, |
179 | const struct GNUNET_PeerIdentity *peer, | 450 | const struct GNUNET_PeerIdentity *peer, |
180 | const GNUNET_HashCode *serv, | 451 | const GNUNET_HashCode *serv, |
@@ -183,7 +454,20 @@ GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *rh, | |||
183 | GNUNET_VPN_AllocationCallback cb, | 454 | GNUNET_VPN_AllocationCallback cb, |
184 | void *cb_cls) | 455 | void *cb_cls) |
185 | { | 456 | { |
186 | return NULL; // FIXME | 457 | struct GNUNET_VPN_RedirectionRequest *rr; |
458 | |||
459 | rr = GNUNET_malloc (sizeof (struct GNUNET_VPN_RedirectionRequest)); | ||
460 | rr->vh = vh; | ||
461 | rr->cb = cb; | ||
462 | rr->cb_cls = cb_cls; | ||
463 | rr->peer = *peer; | ||
464 | rr->serv = *serv; | ||
465 | rr->expiration_time = expiration_time; | ||
466 | rr->result_af = result_af; | ||
467 | rr->nac = nac; | ||
468 | rr->protocol = protocol; | ||
469 | queue_request (rr); | ||
470 | return rr; | ||
187 | } | 471 | } |
188 | 472 | ||
189 | 473 | ||
@@ -213,7 +497,7 @@ GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *rh, | |||
213 | * anyway) | 497 | * anyway) |
214 | */ | 498 | */ |
215 | struct GNUNET_VPN_RedirectionRequest * | 499 | struct GNUNET_VPN_RedirectionRequest * |
216 | GNUNET_VPN_redirect_to_ip (struct GNUNET_VPN_Handle *rh, | 500 | GNUNET_VPN_redirect_to_ip (struct GNUNET_VPN_Handle *vh, |
217 | int result_af, | 501 | int result_af, |
218 | int addr_af, | 502 | int addr_af, |
219 | const void *addr, | 503 | const void *addr, |
@@ -222,7 +506,33 @@ GNUNET_VPN_redirect_to_ip (struct GNUNET_VPN_Handle *rh, | |||
222 | GNUNET_VPN_AllocationCallback cb, | 506 | GNUNET_VPN_AllocationCallback cb, |
223 | void *cb_cls) | 507 | void *cb_cls) |
224 | { | 508 | { |
225 | return NULL; // FIXME | 509 | struct GNUNET_VPN_RedirectionRequest *rr; |
510 | size_t alen; | ||
511 | |||
512 | switch (addr_af) | ||
513 | { | ||
514 | case AF_INET: | ||
515 | alen = sizeof (struct in_addr); | ||
516 | break; | ||
517 | case AF_INET6: | ||
518 | alen = sizeof (struct in6_addr); | ||
519 | break; | ||
520 | default: | ||
521 | GNUNET_break (0); | ||
522 | return NULL; | ||
523 | } | ||
524 | rr = GNUNET_malloc (sizeof (struct GNUNET_VPN_RedirectionRequest) + alen); | ||
525 | rr->vh = vh; | ||
526 | rr->addr = &rr[1]; | ||
527 | rr->cb = cb; | ||
528 | rr->cb_cls = cb_cls; | ||
529 | rr->expiration_time = expiration_time; | ||
530 | rr->result_af = result_af; | ||
531 | rr->addr_af = addr_af; | ||
532 | rr->nac = nac; | ||
533 | memcpy (&rr[1], addr, alen); | ||
534 | queue_request (rr); | ||
535 | return rr; | ||
226 | } | 536 | } |
227 | 537 | ||
228 | 538 | ||
@@ -240,6 +550,11 @@ GNUNET_VPN_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) | |||
240 | vh = GNUNET_malloc (sizeof (struct GNUNET_VPN_Handle)); | 550 | vh = GNUNET_malloc (sizeof (struct GNUNET_VPN_Handle)); |
241 | vh->cfg = cfg; | 551 | vh->cfg = cfg; |
242 | vh->client = GNUNET_CLIENT_connect ("vpn", cfg); | 552 | vh->client = GNUNET_CLIENT_connect ("vpn", cfg); |
553 | if (NULL == vh->client) | ||
554 | { | ||
555 | GNUNET_free (vh); | ||
556 | return NULL; | ||
557 | } | ||
243 | return vh; | 558 | return vh; |
244 | } | 559 | } |
245 | 560 | ||
@@ -253,7 +568,21 @@ void | |||
253 | GNUNET_VPN_disconnect (struct GNUNET_VPN_Handle *vh) | 568 | GNUNET_VPN_disconnect (struct GNUNET_VPN_Handle *vh) |
254 | { | 569 | { |
255 | GNUNET_assert (NULL == vh->rr_head); | 570 | GNUNET_assert (NULL == vh->rr_head); |
256 | GNUNET_CLIENT_disconnect (vh->client, GNUNET_NO); | 571 | if (NULL != vh->th) |
572 | { | ||
573 | GNUNET_CLIENT_notify_transmit_ready_cancel (vh->th); | ||
574 | vh->th = NULL; | ||
575 | } | ||
576 | if (NULL != vh->client) | ||
577 | { | ||
578 | GNUNET_CLIENT_disconnect (vh->client, GNUNET_NO); | ||
579 | vh->client = NULL; | ||
580 | } | ||
581 | if (GNUNET_SCHEDULER_NO_TASK != vh->rt) | ||
582 | { | ||
583 | GNUNET_SCHEDULER_cancel (vh->rt); | ||
584 | vh->rt = GNUNET_SCHEDULER_NO_TASK; | ||
585 | } | ||
257 | GNUNET_free (vh); | 586 | GNUNET_free (vh); |
258 | } | 587 | } |
259 | 588 | ||