diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-12-12 10:44:42 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-12-12 10:44:42 +0000 |
commit | cee16bdcf34ba0ea19b190464e41c62f1c467832 (patch) | |
tree | 32fe29e9e4803ec7c8a8dbcca7d9cb5dc74af3df | |
parent | 8dfec60ba8c701bcec31ac71c3d6f65f0c09570d (diff) | |
download | gnunet-cee16bdcf34ba0ea19b190464e41c62f1c467832.tar.gz gnunet-cee16bdcf34ba0ea19b190464e41c62f1c467832.zip |
-dead
-rw-r--r-- | src/transport/plugin_transport_http.c | 1464 |
1 files changed, 0 insertions, 1464 deletions
diff --git a/src/transport/plugin_transport_http.c b/src/transport/plugin_transport_http.c deleted file mode 100644 index 42743fc96..000000000 --- a/src/transport/plugin_transport_http.c +++ /dev/null | |||
@@ -1,1464 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file transport/plugin_transport_http.c | ||
23 | * @brief http transport service plugin | ||
24 | * @author Matthias Wachs | ||
25 | */ | ||
26 | |||
27 | #include "plugin_transport_http.h" | ||
28 | |||
29 | /** | ||
30 | * After how long do we expire an address that we | ||
31 | * learned from another peer if it is not reconfirmed | ||
32 | * by anyone? | ||
33 | */ | ||
34 | #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Wrapper to manage addresses | ||
39 | */ | ||
40 | struct HttpAddressWrapper | ||
41 | { | ||
42 | /** | ||
43 | * Linked list next | ||
44 | */ | ||
45 | struct HttpAddressWrapper *next; | ||
46 | |||
47 | /** | ||
48 | * Linked list previous | ||
49 | */ | ||
50 | struct HttpAddressWrapper *prev; | ||
51 | |||
52 | struct HttpAddress *addr; | ||
53 | }; | ||
54 | |||
55 | |||
56 | /** | ||
57 | * Encapsulation of all of the state of the plugin. | ||
58 | */ | ||
59 | struct Plugin; | ||
60 | |||
61 | /** | ||
62 | * Start session timeout | ||
63 | */ | ||
64 | static void | ||
65 | start_session_timeout (struct Session *s); | ||
66 | |||
67 | /** | ||
68 | * Increment session timeout due to activity | ||
69 | */ | ||
70 | static void | ||
71 | reschedule_session_timeout (struct Session *s); | ||
72 | |||
73 | /** | ||
74 | * Cancel timeout | ||
75 | */ | ||
76 | static void | ||
77 | stop_session_timeout (struct Session *s); | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Convert the transports address to a nice, human-readable | ||
82 | * format. | ||
83 | * | ||
84 | * @param cls closure | ||
85 | * @param type name of the transport that generated the address | ||
86 | * @param addr one of the addresses of the host, NULL for the last address | ||
87 | * the specific address format depends on the transport | ||
88 | * @param addrlen length of the address | ||
89 | * @param numeric should (IP) addresses be displayed in numeric form? | ||
90 | * @param timeout after how long should we give up? | ||
91 | * @param asc function to call on each string | ||
92 | * @param asc_cls closure for @a asc | ||
93 | */ | ||
94 | static void | ||
95 | http_plugin_address_pretty_printer (void *cls, const char *type, | ||
96 | const void *addr, size_t addrlen, | ||
97 | int numeric, | ||
98 | struct GNUNET_TIME_Relative timeout, | ||
99 | GNUNET_TRANSPORT_AddressStringCallback asc, | ||
100 | void *asc_cls) | ||
101 | { | ||
102 | const struct HttpAddress *haddr = addr; | ||
103 | |||
104 | GNUNET_assert (cls != NULL); | ||
105 | if (addrlen < (sizeof (struct HttpAddress))) | ||
106 | { | ||
107 | /* invalid address */ | ||
108 | GNUNET_break_op (0); | ||
109 | asc (asc_cls, NULL); | ||
110 | return; | ||
111 | } | ||
112 | asc (asc_cls, haddr->addr); | ||
113 | } | ||
114 | |||
115 | |||
116 | |||
117 | /** | ||
118 | * Another peer has suggested an address for this | ||
119 | * peer and transport plugin. Check that this could be a valid | ||
120 | * address. If so, consider adding it to the list | ||
121 | * of addresses. | ||
122 | * | ||
123 | * @param cls closure | ||
124 | * @param addr pointer to the address | ||
125 | * @param addrlen length of addr | ||
126 | * @return GNUNET_OK if this is a plausible address for this peer | ||
127 | * and transport | ||
128 | */ | ||
129 | static int | ||
130 | http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) | ||
131 | { | ||
132 | struct Plugin *plugin = cls; | ||
133 | struct HttpAddressWrapper *w = plugin->addr_head; | ||
134 | struct HttpAddress *haddr = (struct HttpAddress *) addr; | ||
135 | |||
136 | GNUNET_assert (cls != NULL); | ||
137 | |||
138 | if (addrlen <= sizeof (struct HttpAddress)) | ||
139 | return GNUNET_SYSERR; | ||
140 | |||
141 | if (0 == (strcmp (plugin->ext_addr->addr, haddr->addr))) | ||
142 | return GNUNET_OK; | ||
143 | |||
144 | while (NULL != w) | ||
145 | { | ||
146 | if (0 == (strcmp (w->addr->addr, haddr->addr))) | ||
147 | return GNUNET_OK; | ||
148 | w = w->next; | ||
149 | } | ||
150 | return GNUNET_SYSERR; | ||
151 | } | ||
152 | |||
153 | struct GNUNET_TIME_Relative | ||
154 | http_plugin_receive (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
155 | const struct GNUNET_MessageHeader *message, | ||
156 | struct Session *session, const char *sender_address, | ||
157 | uint16_t sender_address_len) | ||
158 | { | ||
159 | struct Session *s = cls; | ||
160 | struct Plugin *plugin = s->plugin; | ||
161 | struct GNUNET_TIME_Relative delay; | ||
162 | struct GNUNET_ATS_Information atsi; | ||
163 | |||
164 | atsi.type = htonl (GNUNET_ATS_NETWORK_TYPE); | ||
165 | atsi.value = session->ats_address_network_type; | ||
166 | GNUNET_break (session->ats_address_network_type != ntohl (GNUNET_ATS_NET_UNSPECIFIED)); | ||
167 | |||
168 | reschedule_session_timeout (session); | ||
169 | |||
170 | delay = | ||
171 | plugin->env->receive (plugin->env->cls, &s->target, message, | ||
172 | &atsi, | ||
173 | 1, s, s->addr, s->addrlen); | ||
174 | return delay; | ||
175 | } | ||
176 | |||
177 | |||
178 | /** | ||
179 | * Function called to convert a string address to | ||
180 | * a binary address. | ||
181 | * | ||
182 | * @param cls closure ('struct Plugin*') | ||
183 | * @param addr string address | ||
184 | * @param addrlen length of the address | ||
185 | * @param buf location to store the buffer | ||
186 | * If the function returns GNUNET_SYSERR, its contents are undefined. | ||
187 | * @param added length of created address | ||
188 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
189 | */ | ||
190 | int | ||
191 | http_string_to_address (void *cls, | ||
192 | const char *addr, | ||
193 | uint16_t addrlen, | ||
194 | void **buf, | ||
195 | size_t *added) | ||
196 | { | ||
197 | #if 0 | ||
198 | #if !BUILD_HTTPS | ||
199 | char *protocol = "http"; | ||
200 | #else | ||
201 | char *protocol = "https"; | ||
202 | #endif | ||
203 | char *addr_str = NULL; | ||
204 | struct sockaddr_in addr_4; | ||
205 | struct sockaddr_in6 addr_6; | ||
206 | struct IPv4HttpAddress * http_4addr; | ||
207 | struct IPv6HttpAddress * http_6addr; | ||
208 | |||
209 | if ((NULL == addr) || (addrlen == 0)) | ||
210 | { | ||
211 | GNUNET_break (0); | ||
212 | return GNUNET_SYSERR; | ||
213 | } | ||
214 | |||
215 | if ('\0' != addr[addrlen - 1]) | ||
216 | { | ||
217 | GNUNET_break (0); | ||
218 | return GNUNET_SYSERR; | ||
219 | } | ||
220 | |||
221 | if (strlen (addr) != addrlen - 1) | ||
222 | { | ||
223 | GNUNET_break (0); | ||
224 | return GNUNET_SYSERR; | ||
225 | } | ||
226 | |||
227 | /* protocoll + "://" + ":" */ | ||
228 | if (addrlen <= (strlen (protocol) + 4)) | ||
229 | { | ||
230 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
231 | "Invalid address string `%s' to convert to address\n", | ||
232 | addr); | ||
233 | GNUNET_break (0); | ||
234 | return GNUNET_SYSERR; | ||
235 | } | ||
236 | |||
237 | if (NULL == (addr_str = strstr(addr, "://"))) | ||
238 | { | ||
239 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
240 | "Invalid address string `%s' to convert to address\n", | ||
241 | addr); | ||
242 | GNUNET_break (0); | ||
243 | return GNUNET_SYSERR; | ||
244 | } | ||
245 | addr_str = &addr_str[3]; | ||
246 | |||
247 | if (addr_str[strlen(addr_str)-1] == '/') | ||
248 | addr_str[strlen(addr_str)-1] = '\0'; | ||
249 | |||
250 | if (GNUNET_OK == GNUNET_STRINGS_to_address_ipv4(addr_str, strlen(addr_str), &addr_4)) | ||
251 | { | ||
252 | http_4addr = GNUNET_malloc (sizeof (struct IPv4HttpAddress)); | ||
253 | http_4addr->u4_port = addr_4.sin_port; | ||
254 | http_4addr->ipv4_addr = (uint32_t) addr_4.sin_addr.s_addr; | ||
255 | (*buf) = http_4addr; | ||
256 | (*added) = sizeof (struct IPv4HttpAddress); | ||
257 | return GNUNET_OK; | ||
258 | } | ||
259 | if (GNUNET_OK == GNUNET_STRINGS_to_address_ipv6(addr_str, strlen(addr_str), &addr_6)) | ||
260 | { | ||
261 | http_6addr = GNUNET_malloc (sizeof (struct IPv6HttpAddress)); | ||
262 | http_6addr->u6_port = addr_6.sin6_port; | ||
263 | http_6addr->ipv6_addr = addr_6.sin6_addr; | ||
264 | (*buf) = http_6addr; | ||
265 | (*added) = sizeof (struct IPv6HttpAddress); | ||
266 | return GNUNET_OK; | ||
267 | } | ||
268 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
269 | "Invalid address string `%s' to convert to address\n", | ||
270 | addr_str); | ||
271 | GNUNET_break (0); | ||
272 | return GNUNET_SYSERR; | ||
273 | #endif | ||
274 | } | ||
275 | |||
276 | |||
277 | /** | ||
278 | * Function called for a quick conversion of the binary address to | ||
279 | * a numeric address. Note that the caller must not free the | ||
280 | * address and that the next call to this function is allowed | ||
281 | * to override the address again. | ||
282 | * | ||
283 | * @param cls closure | ||
284 | * @param addr binary address | ||
285 | * @param addrlen length of the address | ||
286 | * @return string representing the same address | ||
287 | */ | ||
288 | const char * | ||
289 | http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) | ||
290 | { | ||
291 | struct HttpAddress *haddr; | ||
292 | if (addrlen < sizeof (struct HttpAddress)) | ||
293 | { | ||
294 | /* invalid address */ | ||
295 | GNUNET_break (0); | ||
296 | return NULL; | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | haddr = (struct HttpAddress *) addr; | ||
301 | GNUNET_assert (NULL != haddr->addr); | ||
302 | return (const char *) haddr->addr; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | |||
307 | struct Session * | ||
308 | lookup_session_old (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, | ||
309 | struct Session *session, const void *addr, size_t addrlen, | ||
310 | int force_address) | ||
311 | { | ||
312 | struct Session *t; | ||
313 | int e_peer; | ||
314 | int e_addr; | ||
315 | |||
316 | for (t = plugin->head; NULL != t; t = t->next) | ||
317 | { | ||
318 | #if 0 | ||
319 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
320 | "Comparing peer `%s' address `%s' len %i session %p to \n", | ||
321 | GNUNET_i2s (target), GNUNET_a2s (addr, addrlen), addrlen, | ||
322 | session); | ||
323 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
324 | "peer `%s' address `%s' len %i session %p \n\n", | ||
325 | GNUNET_i2s (&t->target), GNUNET_a2s (t->addr, t->addrlen), | ||
326 | t->addrlen, t); | ||
327 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "memcmp %i \n", | ||
328 | memcmp (addr, t->addr, addrlen)); | ||
329 | #endif | ||
330 | e_peer = GNUNET_NO; | ||
331 | e_addr = GNUNET_NO; | ||
332 | if (0 == memcmp (target, &t->target, sizeof (struct GNUNET_PeerIdentity))) | ||
333 | { | ||
334 | e_peer = GNUNET_YES; | ||
335 | if ( (addrlen == t->addrlen) && | ||
336 | (0 == memcmp (addr, t->addr, addrlen)) ) | ||
337 | e_addr = GNUNET_YES; | ||
338 | if ( (t == session) && | ||
339 | (t->addrlen == session->addrlen) && | ||
340 | (0 == memcmp (session->addr, t->addr, t->addrlen)) ) | ||
341 | e_addr = GNUNET_YES; | ||
342 | } | ||
343 | |||
344 | if ( ((e_peer == GNUNET_YES) && (force_address == GNUNET_NO)) || | ||
345 | ((e_peer == GNUNET_YES) && (force_address == GNUNET_YES) && (e_addr == GNUNET_YES)) || | ||
346 | ((e_peer == GNUNET_YES) && (force_address == GNUNET_SYSERR)) ) | ||
347 | return t; | ||
348 | } | ||
349 | return NULL; | ||
350 | } | ||
351 | |||
352 | |||
353 | struct Session * | ||
354 | lookup_session (struct Plugin *plugin, | ||
355 | const struct GNUNET_HELLO_Address *address) | ||
356 | { | ||
357 | struct Session *pos; | ||
358 | |||
359 | for (pos = plugin->head; NULL != pos; pos = pos->next) | ||
360 | if ( (0 == memcmp (&address->peer, &pos->target, sizeof (struct GNUNET_PeerIdentity))) && | ||
361 | (address->address_length == pos->addrlen) && | ||
362 | (0 == memcmp (address->address, pos->addr, pos->addrlen)) ) | ||
363 | return pos; | ||
364 | return NULL; | ||
365 | } | ||
366 | |||
367 | |||
368 | int | ||
369 | exist_session (struct Plugin *plugin, struct Session *s) | ||
370 | { | ||
371 | struct Session * head; | ||
372 | |||
373 | GNUNET_assert (NULL != plugin); | ||
374 | GNUNET_assert (NULL != s); | ||
375 | |||
376 | for (head = plugin->head; head != NULL; head = head->next) | ||
377 | { | ||
378 | if (head == s) | ||
379 | return GNUNET_YES; | ||
380 | } | ||
381 | return GNUNET_NO; | ||
382 | } | ||
383 | |||
384 | /** | ||
385 | * Deleting the session | ||
386 | * Must not be used afterwards | ||
387 | */ | ||
388 | |||
389 | void | ||
390 | delete_session (struct Session *s) | ||
391 | { | ||
392 | struct Plugin *plugin = s->plugin; | ||
393 | stop_session_timeout(s); | ||
394 | |||
395 | GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); | ||
396 | struct HTTP_Message *msg = s->msg_head; | ||
397 | struct HTTP_Message *tmp = NULL; | ||
398 | |||
399 | while (msg != NULL) | ||
400 | { | ||
401 | tmp = msg->next; | ||
402 | |||
403 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
404 | if (msg->transmit_cont != NULL) | ||
405 | { | ||
406 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); | ||
407 | } | ||
408 | GNUNET_free (msg); | ||
409 | msg = tmp; | ||
410 | } | ||
411 | |||
412 | if (s->msg_tk != NULL) | ||
413 | { | ||
414 | GNUNET_SERVER_mst_destroy (s->msg_tk); | ||
415 | s->msg_tk = NULL; | ||
416 | } | ||
417 | GNUNET_free (s->addr); | ||
418 | GNUNET_free_non_null (s->server_recv); | ||
419 | GNUNET_free_non_null (s->server_send); | ||
420 | GNUNET_free (s); | ||
421 | } | ||
422 | |||
423 | |||
424 | struct Session * | ||
425 | create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, | ||
426 | const void *addr, size_t addrlen) | ||
427 | { | ||
428 | struct Session *s = NULL; | ||
429 | struct GNUNET_ATS_Information ats; | ||
430 | |||
431 | /* | ||
432 | * ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s6, sizeof (struct sockaddr_in6)); | ||
433 | */ | ||
434 | if (addrlen < sizeof (struct HttpAddress)) | ||
435 | { | ||
436 | GNUNET_break (0); | ||
437 | return NULL; | ||
438 | } | ||
439 | |||
440 | |||
441 | |||
442 | s = GNUNET_malloc (sizeof (struct Session)); | ||
443 | memcpy (&s->target, target, sizeof (struct GNUNET_PeerIdentity)); | ||
444 | s->plugin = plugin; | ||
445 | s->addr = GNUNET_malloc (addrlen); | ||
446 | memcpy (s->addr, addr, addrlen); | ||
447 | s->addrlen = addrlen; | ||
448 | s->ats_address_network_type = ats.value; | ||
449 | |||
450 | |||
451 | start_session_timeout(s); | ||
452 | return s; | ||
453 | } | ||
454 | |||
455 | |||
456 | void | ||
457 | notify_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
458 | struct Session *s) | ||
459 | { | ||
460 | struct Plugin *plugin = cls; | ||
461 | |||
462 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
463 | "Notifying transport about ending session %p (`%s')\n", | ||
464 | s, | ||
465 | http_plugin_address_to_string(NULL, s->addr,s->addrlen)); | ||
466 | |||
467 | plugin->env->session_end (plugin->env->cls, peer, s); | ||
468 | delete_session (s); | ||
469 | } | ||
470 | |||
471 | |||
472 | /** | ||
473 | * Creates a new outbound session the transport service will use to send data to the | ||
474 | * peer | ||
475 | * | ||
476 | * @param cls the plugin | ||
477 | * @param address the address | ||
478 | * @return the session or NULL of max connections exceeded | ||
479 | */ | ||
480 | static struct Session * | ||
481 | http_get_session (void *cls, | ||
482 | const struct GNUNET_HELLO_Address *address) | ||
483 | { | ||
484 | struct Plugin *plugin = cls; | ||
485 | struct Session * s = NULL; | ||
486 | size_t addrlen; | ||
487 | |||
488 | GNUNET_assert (plugin != NULL); | ||
489 | GNUNET_assert (address != NULL); | ||
490 | GNUNET_assert (address->address != NULL); | ||
491 | |||
492 | /* find existing session */ | ||
493 | s = lookup_session (plugin, address); | ||
494 | if (s != NULL) | ||
495 | return s; | ||
496 | |||
497 | if (plugin->max_connections <= plugin->cur_connections) | ||
498 | { | ||
499 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, | ||
500 | "Maximum number of connections reached, " | ||
501 | "cannot connect to peer `%s'\n", GNUNET_i2s (&address->peer)); | ||
502 | return NULL; | ||
503 | } | ||
504 | |||
505 | /* create new session */ | ||
506 | addrlen = address->address_length; | ||
507 | |||
508 | GNUNET_assert (addrlen > sizeof (struct HttpAddress)); | ||
509 | |||
510 | s = create_session (plugin, &address->peer, address->address, address->address_length); | ||
511 | |||
512 | /* add new session */ | ||
513 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); | ||
514 | /* initiate new connection */ | ||
515 | if (GNUNET_SYSERR == client_connect (s)) | ||
516 | { | ||
517 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
518 | "Cannot connect to peer `%s' address `%s''\n", | ||
519 | http_plugin_address_to_string(NULL, s->addr, s->addrlen), | ||
520 | GNUNET_i2s (&s->target)); | ||
521 | GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); | ||
522 | delete_session (s); | ||
523 | return NULL; | ||
524 | } | ||
525 | |||
526 | return s; | ||
527 | } | ||
528 | |||
529 | |||
530 | /** | ||
531 | * Function that can be used by the transport service to transmit | ||
532 | * a message using the plugin. Note that in the case of a | ||
533 | * peer disconnecting, the continuation MUST be called | ||
534 | * prior to the disconnect notification itself. This function | ||
535 | * will be called with this peer's HELLO message to initiate | ||
536 | * a fresh connection to another peer. | ||
537 | * | ||
538 | * @param cls closure | ||
539 | * @param session which session must be used | ||
540 | * @param msgbuf the message to transmit | ||
541 | * @param msgbuf_size number of bytes in 'msgbuf' | ||
542 | * @param priority how important is the message (most plugins will | ||
543 | * ignore message priority and just FIFO) | ||
544 | * @param to how long to wait at most for the transmission (does not | ||
545 | * require plugins to discard the message after the timeout, | ||
546 | * just advisory for the desired delay; most plugins will ignore | ||
547 | * this as well) | ||
548 | * @param cont continuation to call once the message has | ||
549 | * been transmitted (or if the transport is ready | ||
550 | * for the next transmission call; or if the | ||
551 | * peer disconnected...); can be NULL | ||
552 | * @param cont_cls closure for cont | ||
553 | * @return number of bytes used (on the physical network, with overheads); | ||
554 | * -1 on hard errors (i.e. address invalid); 0 is a legal value | ||
555 | * and does NOT mean that the message was not transmitted (DV) | ||
556 | */ | ||
557 | static ssize_t | ||
558 | http_plugin_send (void *cls, | ||
559 | struct Session *session, | ||
560 | const char *msgbuf, size_t msgbuf_size, | ||
561 | unsigned int priority, | ||
562 | struct GNUNET_TIME_Relative to, | ||
563 | GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) | ||
564 | { | ||
565 | struct Plugin *plugin = cls; | ||
566 | struct HTTP_Message *msg; | ||
567 | struct Session *tmp; | ||
568 | size_t res = -1; | ||
569 | |||
570 | GNUNET_assert (plugin != NULL); | ||
571 | GNUNET_assert (session != NULL); | ||
572 | |||
573 | /* lookup if session is really existing */ | ||
574 | tmp = plugin->head; | ||
575 | while (tmp != NULL) | ||
576 | { | ||
577 | if ((tmp == session) && | ||
578 | (0 == memcmp (&session->target, &tmp->target, sizeof (struct GNUNET_PeerIdentity))) && | ||
579 | (session->addrlen == tmp->addrlen) && | ||
580 | (0 == memcmp (session->addr, tmp->addr, tmp->addrlen))) | ||
581 | break; | ||
582 | tmp = tmp->next; | ||
583 | } | ||
584 | if (tmp == NULL) | ||
585 | { | ||
586 | GNUNET_break_op (0); | ||
587 | return res; | ||
588 | } | ||
589 | |||
590 | /* create new message and schedule */ | ||
591 | msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size); | ||
592 | msg->next = NULL; | ||
593 | msg->size = msgbuf_size; | ||
594 | msg->pos = 0; | ||
595 | msg->buf = (char *) &msg[1]; | ||
596 | msg->transmit_cont = cont; | ||
597 | msg->transmit_cont_cls = cont_cls; | ||
598 | memcpy (msg->buf, msgbuf, msgbuf_size); | ||
599 | |||
600 | reschedule_session_timeout (session); | ||
601 | |||
602 | if (session->inbound == GNUNET_NO) | ||
603 | { | ||
604 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
605 | "Using outbound client session %p to send to `%s'\n", session, | ||
606 | GNUNET_i2s (&session->target)); | ||
607 | client_send (session, msg); | ||
608 | res = msgbuf_size; | ||
609 | } | ||
610 | if (session->inbound == GNUNET_YES) | ||
611 | { | ||
612 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
613 | "Using inbound server %p session to send to `%s'\n", session, | ||
614 | GNUNET_i2s (&session->target)); | ||
615 | server_send (session, msg); | ||
616 | res = msgbuf_size; | ||
617 | } | ||
618 | return res; | ||
619 | |||
620 | } | ||
621 | |||
622 | |||
623 | /** | ||
624 | * Function that can be used to force the plugin to disconnect | ||
625 | * from the given peer and cancel all previous transmissions | ||
626 | * (and their continuationc). | ||
627 | * | ||
628 | * @param cls closure | ||
629 | * @param target peer from which to disconnect | ||
630 | */ | ||
631 | static void | ||
632 | http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) | ||
633 | { | ||
634 | struct Plugin *plugin = cls; | ||
635 | struct Session *next = NULL; | ||
636 | struct Session *s = plugin->head; | ||
637 | |||
638 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
639 | "Transport tells me to disconnect `%s'\n", | ||
640 | GNUNET_i2s (target)); | ||
641 | while (s != NULL) | ||
642 | { | ||
643 | next = s->next; | ||
644 | if (0 == memcmp (target, &s->target, sizeof (struct GNUNET_PeerIdentity))) | ||
645 | { | ||
646 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
647 | "Disconnecting %s session %p to `%s'\n", | ||
648 | (s->inbound == GNUNET_NO) ? "outbound" : "inbound", | ||
649 | s, GNUNET_i2s (target)); | ||
650 | |||
651 | if (s->inbound == GNUNET_NO) | ||
652 | GNUNET_assert (GNUNET_OK == client_disconnect (s)); | ||
653 | else | ||
654 | GNUNET_assert (GNUNET_OK == server_disconnect (s)); | ||
655 | } | ||
656 | s = next; | ||
657 | } | ||
658 | } | ||
659 | |||
660 | |||
661 | static void * | ||
662 | find_address (struct Plugin *plugin, const struct sockaddr *addr, socklen_t addrlen) | ||
663 | { | ||
664 | struct HttpAddressWrapper *w = NULL; | ||
665 | char *saddr; | ||
666 | |||
667 | GNUNET_asprintf(&saddr, "%s://%s", plugin->protocol, GNUNET_a2s (addr, addrlen)); | ||
668 | w = plugin->addr_head; | ||
669 | while (NULL != w) | ||
670 | { | ||
671 | if (0 == strcmp (saddr, w->addr->addr)) | ||
672 | break; | ||
673 | w = w->next; | ||
674 | } | ||
675 | |||
676 | GNUNET_free (saddr); | ||
677 | return w; | ||
678 | } | ||
679 | |||
680 | |||
681 | |||
682 | |||
683 | static void | ||
684 | nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, | ||
685 | socklen_t addrlen) | ||
686 | { | ||
687 | struct Plugin *plugin = cls; | ||
688 | struct HttpAddressWrapper *w = NULL; | ||
689 | char *saddr; | ||
690 | size_t haddrlen; | ||
691 | |||
692 | GNUNET_asprintf(&saddr, "%s://%s", plugin->protocol, GNUNET_a2s (addr, addrlen)); | ||
693 | |||
694 | haddrlen = sizeof (struct HttpAddress) + strlen(saddr) + 1; | ||
695 | w = GNUNET_malloc (sizeof (struct HttpAddressWrapper)); | ||
696 | w->addr = GNUNET_malloc (haddrlen); | ||
697 | w->addr->addr = &w->addr[1]; | ||
698 | w->addr->addr_len = htonl (strlen(saddr) + 1); | ||
699 | memcpy (w->addr->addr, saddr, strlen(saddr) + 1); | ||
700 | GNUNET_free (saddr); | ||
701 | |||
702 | GNUNET_CONTAINER_DLL_insert(plugin->addr_head, plugin->addr_tail, w); | ||
703 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
704 | "Notifying transport to add address `%s'\n", w->addr->addr); | ||
705 | |||
706 | plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, haddrlen, "http"); | ||
707 | } | ||
708 | |||
709 | |||
710 | static void | ||
711 | nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr, | ||
712 | socklen_t addrlen) | ||
713 | { | ||
714 | struct Plugin *plugin = cls; | ||
715 | struct HttpAddressWrapper *w = NULL; | ||
716 | size_t haddrlen; | ||
717 | |||
718 | w = find_address (plugin, addr, addrlen); | ||
719 | if (NULL == w) | ||
720 | return; | ||
721 | |||
722 | haddrlen = sizeof (struct HttpAddress) + ntohl (w->addr->addr_len); | ||
723 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
724 | "Notifying transport to remove address `%s'\n", http_plugin_address_to_string(NULL, w->addr, haddrlen)); | ||
725 | |||
726 | |||
727 | GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w); | ||
728 | plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, | ||
729 | sizeof (struct HttpAddress) + ntohl (w->addr->addr_len), "http"); | ||
730 | GNUNET_free (w->addr); | ||
731 | GNUNET_free (w); | ||
732 | } | ||
733 | |||
734 | |||
735 | /** | ||
736 | * Our external IP address/port mapping has changed. | ||
737 | * | ||
738 | * @param cls closure, the 'struct LocalAddrList' | ||
739 | * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean | ||
740 | * the previous (now invalid) one | ||
741 | * @param addr either the previous or the new public IP address | ||
742 | * @param addrlen actual lenght of the address | ||
743 | */ | ||
744 | static void | ||
745 | nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr, | ||
746 | socklen_t addrlen) | ||
747 | { | ||
748 | GNUNET_assert (cls != NULL); | ||
749 | struct Plugin *plugin = cls; | ||
750 | |||
751 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
752 | "NPMC called %s to address `%s'\n", | ||
753 | (add_remove == GNUNET_NO) ? "remove" : "add", | ||
754 | GNUNET_a2s (addr, addrlen)); | ||
755 | |||
756 | switch (add_remove) | ||
757 | { | ||
758 | case GNUNET_YES: | ||
759 | nat_add_address (cls, add_remove, addr, addrlen); | ||
760 | break; | ||
761 | case GNUNET_NO: | ||
762 | nat_remove_address (cls, add_remove, addr, addrlen); | ||
763 | break; | ||
764 | } | ||
765 | } | ||
766 | |||
767 | |||
768 | void | ||
769 | http_check_ipv6 (struct Plugin *plugin) | ||
770 | { | ||
771 | struct GNUNET_NETWORK_Handle *desc = NULL; | ||
772 | |||
773 | if (plugin->ipv6 == GNUNET_YES) | ||
774 | { | ||
775 | /* probe IPv6 support */ | ||
776 | desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); | ||
777 | if (NULL == desc) | ||
778 | { | ||
779 | if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || | ||
780 | (errno == EACCES)) | ||
781 | { | ||
782 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); | ||
783 | } | ||
784 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, | ||
785 | _ | ||
786 | ("Disabling IPv6 since it is not supported on this system!\n")); | ||
787 | plugin->ipv6 = GNUNET_NO; | ||
788 | } | ||
789 | else | ||
790 | { | ||
791 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); | ||
792 | desc = NULL; | ||
793 | } | ||
794 | |||
795 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
796 | "Testing IPv6 on this system: %s\n", | ||
797 | (plugin->ipv6 == GNUNET_YES) ? "successful" : "failed"); | ||
798 | } | ||
799 | } | ||
800 | |||
801 | |||
802 | int | ||
803 | http_get_addresses (struct Plugin *plugin, const char *service_name, | ||
804 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
805 | struct sockaddr ***addrs, socklen_t ** addr_lens) | ||
806 | { | ||
807 | int disablev6; | ||
808 | unsigned long long port; | ||
809 | struct addrinfo hints; | ||
810 | struct addrinfo *res; | ||
811 | struct addrinfo *pos; | ||
812 | struct addrinfo *next; | ||
813 | unsigned int i; | ||
814 | int resi; | ||
815 | int ret; | ||
816 | struct sockaddr **saddrs; | ||
817 | socklen_t *saddrlens; | ||
818 | char *hostname; | ||
819 | |||
820 | *addrs = NULL; | ||
821 | *addr_lens = NULL; | ||
822 | |||
823 | disablev6 = !plugin->ipv6; | ||
824 | |||
825 | port = 0; | ||
826 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) | ||
827 | { | ||
828 | GNUNET_break (GNUNET_OK == | ||
829 | GNUNET_CONFIGURATION_get_value_number (cfg, service_name, | ||
830 | "PORT", &port)); | ||
831 | if (port > 65535) | ||
832 | { | ||
833 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
834 | _ | ||
835 | ("Require valid port number for service in configuration!\n")); | ||
836 | return GNUNET_SYSERR; | ||
837 | } | ||
838 | } | ||
839 | if (0 == port) | ||
840 | { | ||
841 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, plugin->name, | ||
842 | "Starting in listen only mode\n"); | ||
843 | return -1; /* listen only */ | ||
844 | } | ||
845 | |||
846 | |||
847 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO")) | ||
848 | { | ||
849 | GNUNET_break (GNUNET_OK == | ||
850 | GNUNET_CONFIGURATION_get_value_string (cfg, service_name, | ||
851 | "BINDTO", &hostname)); | ||
852 | } | ||
853 | else | ||
854 | hostname = NULL; | ||
855 | |||
856 | if (hostname != NULL) | ||
857 | { | ||
858 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
859 | "Resolving `%s' since that is where `%s' will bind to.\n", | ||
860 | hostname, service_name); | ||
861 | memset (&hints, 0, sizeof (struct addrinfo)); | ||
862 | if (disablev6) | ||
863 | hints.ai_family = AF_INET; | ||
864 | if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || | ||
865 | (res == NULL)) | ||
866 | { | ||
867 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"), | ||
868 | hostname, gai_strerror (ret)); | ||
869 | GNUNET_free (hostname); | ||
870 | return GNUNET_SYSERR; | ||
871 | } | ||
872 | next = res; | ||
873 | i = 0; | ||
874 | while (NULL != (pos = next)) | ||
875 | { | ||
876 | next = pos->ai_next; | ||
877 | if ((disablev6) && (pos->ai_family == AF_INET6)) | ||
878 | continue; | ||
879 | i++; | ||
880 | } | ||
881 | if (0 == i) | ||
882 | { | ||
883 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
884 | _("Failed to find %saddress for `%s'.\n"), | ||
885 | disablev6 ? "IPv4 " : "", hostname); | ||
886 | freeaddrinfo (res); | ||
887 | GNUNET_free (hostname); | ||
888 | return GNUNET_SYSERR; | ||
889 | } | ||
890 | resi = i; | ||
891 | saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); | ||
892 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); | ||
893 | i = 0; | ||
894 | next = res; | ||
895 | while (NULL != (pos = next)) | ||
896 | { | ||
897 | next = pos->ai_next; | ||
898 | if ((disablev6) && (pos->ai_family == AF_INET6)) | ||
899 | continue; | ||
900 | if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0)) | ||
901 | continue; /* not TCP */ | ||
902 | if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0)) | ||
903 | continue; /* huh? */ | ||
904 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
905 | "Service will bind to `%s'\n", GNUNET_a2s (pos->ai_addr, | ||
906 | pos->ai_addrlen)); | ||
907 | if (pos->ai_family == AF_INET) | ||
908 | { | ||
909 | GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in)); | ||
910 | saddrlens[i] = pos->ai_addrlen; | ||
911 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
912 | memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); | ||
913 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | ||
914 | } | ||
915 | else | ||
916 | { | ||
917 | GNUNET_assert (pos->ai_family == AF_INET6); | ||
918 | GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6)); | ||
919 | saddrlens[i] = pos->ai_addrlen; | ||
920 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
921 | memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); | ||
922 | ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); | ||
923 | } | ||
924 | i++; | ||
925 | } | ||
926 | GNUNET_free (hostname); | ||
927 | freeaddrinfo (res); | ||
928 | resi = i; | ||
929 | } | ||
930 | else | ||
931 | { | ||
932 | /* will bind against everything, just set port */ | ||
933 | if (disablev6) | ||
934 | { | ||
935 | /* V4-only */ | ||
936 | resi = 1; | ||
937 | i = 0; | ||
938 | saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); | ||
939 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); | ||
940 | |||
941 | saddrlens[i] = sizeof (struct sockaddr_in); | ||
942 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
943 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
944 | ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i]; | ||
945 | #endif | ||
946 | ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; | ||
947 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | ||
948 | } | ||
949 | else | ||
950 | { | ||
951 | /* dual stack */ | ||
952 | resi = 2; | ||
953 | saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); | ||
954 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); | ||
955 | i = 0; | ||
956 | saddrlens[i] = sizeof (struct sockaddr_in6); | ||
957 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
958 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
959 | ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0]; | ||
960 | #endif | ||
961 | ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6; | ||
962 | ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); | ||
963 | i++; | ||
964 | saddrlens[i] = sizeof (struct sockaddr_in); | ||
965 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
966 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
967 | ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1]; | ||
968 | #endif | ||
969 | ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; | ||
970 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | ||
971 | } | ||
972 | } | ||
973 | *addrs = saddrs; | ||
974 | *addr_lens = saddrlens; | ||
975 | return resi; | ||
976 | } | ||
977 | |||
978 | static void | ||
979 | start_report_addresses (struct Plugin *plugin) | ||
980 | { | ||
981 | int res = GNUNET_OK; | ||
982 | struct sockaddr **addrs; | ||
983 | socklen_t *addrlens; | ||
984 | |||
985 | res = | ||
986 | http_get_addresses (plugin, plugin->name, plugin->env->cfg, &addrs, | ||
987 | &addrlens); | ||
988 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
989 | _("Found %u addresses to report to NAT service\n"), res); | ||
990 | |||
991 | if (GNUNET_SYSERR == res) | ||
992 | { | ||
993 | plugin->nat = NULL; | ||
994 | return; | ||
995 | } | ||
996 | |||
997 | plugin->nat = | ||
998 | GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port, | ||
999 | (unsigned int) res, | ||
1000 | (const struct sockaddr **) addrs, addrlens, | ||
1001 | &nat_port_map_callback, NULL, plugin); | ||
1002 | while (res > 0) | ||
1003 | { | ||
1004 | res--; | ||
1005 | GNUNET_assert (addrs[res] != NULL); | ||
1006 | GNUNET_free (addrs[res]); | ||
1007 | } | ||
1008 | GNUNET_free_non_null (addrs); | ||
1009 | GNUNET_free_non_null (addrlens); | ||
1010 | } | ||
1011 | |||
1012 | |||
1013 | static void | ||
1014 | stop_report_addresses (struct Plugin *plugin) | ||
1015 | { | ||
1016 | |||
1017 | /* Stop NAT handle */ | ||
1018 | if (NULL != plugin->nat) | ||
1019 | GNUNET_NAT_unregister (plugin->nat); | ||
1020 | |||
1021 | /* Clean up addresses */ | ||
1022 | struct HttpAddressWrapper *w; | ||
1023 | |||
1024 | while (plugin->addr_head != NULL) | ||
1025 | { | ||
1026 | w = plugin->addr_head; | ||
1027 | GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w); | ||
1028 | GNUNET_free (w->addr); | ||
1029 | GNUNET_free (w); | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | /** | ||
1034 | * Function called when the service shuts down. Unloads our plugins | ||
1035 | * and cancels pending validations. | ||
1036 | * | ||
1037 | * @param cls closure, unused | ||
1038 | * @param tc task context (unused) | ||
1039 | */ | ||
1040 | static void | ||
1041 | notify_external_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1042 | { | ||
1043 | struct Plugin *plugin = cls; | ||
1044 | struct HttpAddress *eaddr; | ||
1045 | char *addr; | ||
1046 | size_t eaddr_len; | ||
1047 | size_t uri_len; | ||
1048 | |||
1049 | plugin->notify_ext_task = GNUNET_SCHEDULER_NO_TASK; | ||
1050 | |||
1051 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1052 | return; | ||
1053 | |||
1054 | GNUNET_asprintf(&addr, "%s://%s", plugin->protocol, plugin->external_hostname); | ||
1055 | uri_len = strlen (addr) + 1; | ||
1056 | eaddr_len = sizeof (struct HttpAddress) + uri_len; | ||
1057 | eaddr = GNUNET_malloc (eaddr_len); | ||
1058 | eaddr->addr_len = htonl (uri_len); | ||
1059 | eaddr->addr = (void *) &eaddr[1]; | ||
1060 | memcpy (&eaddr->addr, addr, uri_len); | ||
1061 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1062 | "Notifying transport about external hostname address `%s'\n", addr); | ||
1063 | |||
1064 | GNUNET_free (addr); | ||
1065 | plugin->env->notify_address (plugin->env->cls, GNUNET_YES, eaddr, eaddr_len, "http"); | ||
1066 | plugin->ext_addr = eaddr; | ||
1067 | plugin->ext_addr_len = eaddr_len; | ||
1068 | } | ||
1069 | |||
1070 | |||
1071 | static int | ||
1072 | configure_plugin (struct Plugin *plugin) | ||
1073 | { | ||
1074 | int res = GNUNET_OK; | ||
1075 | |||
1076 | /* Use IPv4? */ | ||
1077 | if (GNUNET_CONFIGURATION_have_value | ||
1078 | (plugin->env->cfg, plugin->name, "USE_IPv4")) | ||
1079 | { | ||
1080 | plugin->ipv4 = | ||
1081 | GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, | ||
1082 | "USE_IPv4"); | ||
1083 | } | ||
1084 | else | ||
1085 | plugin->ipv4 = GNUNET_YES; | ||
1086 | |||
1087 | /* Use IPv6? */ | ||
1088 | if (GNUNET_CONFIGURATION_have_value | ||
1089 | (plugin->env->cfg, plugin->name, "USE_IPv6")) | ||
1090 | { | ||
1091 | plugin->ipv6 = | ||
1092 | GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, | ||
1093 | "USE_IPv6"); | ||
1094 | } | ||
1095 | else | ||
1096 | plugin->ipv6 = GNUNET_YES; | ||
1097 | |||
1098 | if ((plugin->ipv4 == GNUNET_NO) && (plugin->ipv6 == GNUNET_NO)) | ||
1099 | { | ||
1100 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1101 | _ | ||
1102 | ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"), | ||
1103 | plugin->name); | ||
1104 | res = GNUNET_SYSERR; | ||
1105 | } | ||
1106 | |||
1107 | /* Reading port number from config file */ | ||
1108 | unsigned long long port; | ||
1109 | |||
1110 | if ((GNUNET_OK != | ||
1111 | GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name, | ||
1112 | "PORT", &port)) || (port > 65535)) | ||
1113 | { | ||
1114 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1115 | _("Port is required! Fix in configuration\n"), | ||
1116 | plugin->name); | ||
1117 | res = GNUNET_SYSERR; | ||
1118 | goto fail; | ||
1119 | } | ||
1120 | plugin->port = port; | ||
1121 | |||
1122 | plugin->client_only = GNUNET_NO; | ||
1123 | if (plugin->port == 0) | ||
1124 | { | ||
1125 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1126 | _("Port 0, client only mode\n")); | ||
1127 | plugin->client_only = GNUNET_YES; | ||
1128 | } | ||
1129 | |||
1130 | char *bind4_address = NULL; | ||
1131 | |||
1132 | if ((plugin->ipv4 == GNUNET_YES) && | ||
1133 | (GNUNET_YES == | ||
1134 | GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, | ||
1135 | "BINDTO", &bind4_address))) | ||
1136 | { | ||
1137 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1138 | "Binding %s plugin to specific IPv4 address: `%s'\n", | ||
1139 | plugin->protocol, bind4_address); | ||
1140 | plugin->server_addr_v4 = GNUNET_malloc (sizeof (struct sockaddr_in)); | ||
1141 | if (1 != | ||
1142 | inet_pton (AF_INET, bind4_address, &plugin->server_addr_v4->sin_addr)) | ||
1143 | { | ||
1144 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1145 | _ | ||
1146 | ("Specific IPv4 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"), | ||
1147 | bind4_address, plugin->protocol); | ||
1148 | GNUNET_free (plugin->server_addr_v4); | ||
1149 | plugin->server_addr_v4 = NULL; | ||
1150 | } | ||
1151 | else | ||
1152 | { | ||
1153 | plugin->server_addr_v4->sin_family = AF_INET; | ||
1154 | plugin->server_addr_v4->sin_port = htons (plugin->port); | ||
1155 | } | ||
1156 | GNUNET_free (bind4_address); | ||
1157 | } | ||
1158 | |||
1159 | char *bind6_address = NULL; | ||
1160 | |||
1161 | if ((plugin->ipv6 == GNUNET_YES) && | ||
1162 | (GNUNET_YES == | ||
1163 | GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, | ||
1164 | "BINDTO6", &bind6_address))) | ||
1165 | { | ||
1166 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1167 | "Binding %s plugin to specific IPv6 address: `%s'\n", | ||
1168 | plugin->protocol, bind6_address); | ||
1169 | plugin->server_addr_v6 = GNUNET_malloc (sizeof (struct sockaddr_in6)); | ||
1170 | if (1 != | ||
1171 | inet_pton (AF_INET6, bind6_address, &plugin->server_addr_v6->sin6_addr)) | ||
1172 | { | ||
1173 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1174 | _ | ||
1175 | ("Specific IPv6 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"), | ||
1176 | bind6_address, plugin->protocol); | ||
1177 | GNUNET_free (plugin->server_addr_v6); | ||
1178 | plugin->server_addr_v6 = NULL; | ||
1179 | } | ||
1180 | else | ||
1181 | { | ||
1182 | plugin->server_addr_v6->sin6_family = AF_INET6; | ||
1183 | plugin->server_addr_v6->sin6_port = htons (plugin->port); | ||
1184 | } | ||
1185 | GNUNET_free (bind6_address); | ||
1186 | } | ||
1187 | |||
1188 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, | ||
1189 | "EXTERNAL_HOSTNAME", &plugin->external_hostname)) | ||
1190 | { | ||
1191 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1192 | _("Using external hostname `%s'\n"), plugin->external_hostname); | ||
1193 | plugin->notify_ext_task = GNUNET_SCHEDULER_add_now (¬ify_external_hostname, plugin); | ||
1194 | } | ||
1195 | else | ||
1196 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1197 | _("No external hostname configured\n")); | ||
1198 | |||
1199 | |||
1200 | /* Optional parameters */ | ||
1201 | unsigned long long maxneigh; | ||
1202 | |||
1203 | if (GNUNET_OK != | ||
1204 | GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name, | ||
1205 | "MAX_CONNECTIONS", &maxneigh)) | ||
1206 | maxneigh = 128; | ||
1207 | plugin->max_connections = maxneigh; | ||
1208 | |||
1209 | fail: | ||
1210 | return res; | ||
1211 | } | ||
1212 | |||
1213 | #define TESTING GNUNET_NO | ||
1214 | |||
1215 | #if TESTING | ||
1216 | #define TIMEOUT_LOG GNUNET_ERROR_TYPE_ERROR | ||
1217 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
1218 | #else | ||
1219 | #define TIMEOUT_LOG GNUNET_ERROR_TYPE_DEBUG | ||
1220 | #define TIMEOUT GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT | ||
1221 | #endif | ||
1222 | |||
1223 | |||
1224 | /** | ||
1225 | * Session was idle, so disconnect it | ||
1226 | */ | ||
1227 | static void | ||
1228 | session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1229 | { | ||
1230 | GNUNET_assert (NULL != cls); | ||
1231 | struct Session *s = cls; | ||
1232 | |||
1233 | s->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
1234 | GNUNET_log (TIMEOUT_LOG, | ||
1235 | "Session %p was idle for %s, disconnecting\n", | ||
1236 | s, | ||
1237 | GNUNET_STRINGS_relative_time_to_string (TIMEOUT, | ||
1238 | GNUNET_YES)); | ||
1239 | |||
1240 | /* call session destroy function */ | ||
1241 | if (s->inbound == GNUNET_NO) | ||
1242 | GNUNET_assert (GNUNET_OK == client_disconnect (s)); | ||
1243 | else | ||
1244 | GNUNET_assert (GNUNET_OK == server_disconnect (s)); | ||
1245 | } | ||
1246 | |||
1247 | |||
1248 | /** | ||
1249 | * Start session timeout | ||
1250 | */ | ||
1251 | static void | ||
1252 | start_session_timeout (struct Session *s) | ||
1253 | { | ||
1254 | GNUNET_assert (NULL != s); | ||
1255 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task); | ||
1256 | s->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
1257 | &session_timeout, | ||
1258 | s); | ||
1259 | GNUNET_log (TIMEOUT_LOG, | ||
1260 | "Timeout for session %p set to %s\n", | ||
1261 | s, | ||
1262 | GNUNET_STRINGS_relative_time_to_string (TIMEOUT, | ||
1263 | GNUNET_YES)); | ||
1264 | } | ||
1265 | |||
1266 | |||
1267 | /** | ||
1268 | * Increment session timeout due to activity | ||
1269 | */ | ||
1270 | static void | ||
1271 | reschedule_session_timeout (struct Session *s) | ||
1272 | { | ||
1273 | GNUNET_assert (NULL != s); | ||
1274 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task); | ||
1275 | |||
1276 | GNUNET_SCHEDULER_cancel (s->timeout_task); | ||
1277 | s->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
1278 | &session_timeout, | ||
1279 | s); | ||
1280 | GNUNET_log (TIMEOUT_LOG, | ||
1281 | "Timeout rescheduled for session %p set to %s\n", | ||
1282 | s, | ||
1283 | GNUNET_STRINGS_relative_time_to_String (TIMEOUT, | ||
1284 | GNUNET_YES)); | ||
1285 | } | ||
1286 | |||
1287 | |||
1288 | /** | ||
1289 | * Cancel timeout | ||
1290 | */ | ||
1291 | static void | ||
1292 | stop_session_timeout (struct Session *s) | ||
1293 | { | ||
1294 | GNUNET_assert (NULL != s); | ||
1295 | |||
1296 | if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) | ||
1297 | { | ||
1298 | GNUNET_SCHEDULER_cancel (s->timeout_task); | ||
1299 | s->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
1300 | GNUNET_log (TIMEOUT_LOG, | ||
1301 | "Timeout stopped for session %p\n", | ||
1302 | s); | ||
1303 | } | ||
1304 | } | ||
1305 | |||
1306 | /** | ||
1307 | * Entry point for the plugin. | ||
1308 | */ | ||
1309 | void * | ||
1310 | LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) | ||
1311 | { | ||
1312 | struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; | ||
1313 | struct GNUNET_TRANSPORT_PluginFunctions *api; | ||
1314 | struct Plugin *plugin; | ||
1315 | int res; | ||
1316 | |||
1317 | if (NULL == env->receive) | ||
1318 | { | ||
1319 | /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully | ||
1320 | initialze the plugin or the API */ | ||
1321 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); | ||
1322 | api->cls = NULL; | ||
1323 | api->address_pretty_printer = &http_plugin_address_pretty_printer; | ||
1324 | api->address_to_string = &http_plugin_address_to_string; | ||
1325 | api->string_to_address = &http_string_to_address; | ||
1326 | return api; | ||
1327 | } | ||
1328 | |||
1329 | plugin = GNUNET_malloc (sizeof (struct Plugin)); | ||
1330 | plugin->env = env; | ||
1331 | plugin->outbound_sessions = 0; | ||
1332 | plugin->inbound_sessions = 0; | ||
1333 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); | ||
1334 | api->cls = plugin; | ||
1335 | api->disconnect = &http_plugin_disconnect; | ||
1336 | api->address_pretty_printer = &http_plugin_address_pretty_printer; | ||
1337 | api->check_address = &http_plugin_address_suggested; | ||
1338 | api->address_to_string = &http_plugin_address_to_string; | ||
1339 | api->string_to_address = &http_string_to_address; | ||
1340 | api->get_session = &http_get_session; | ||
1341 | api->send = &http_plugin_send; | ||
1342 | |||
1343 | #if BUILD_HTTPS | ||
1344 | plugin->name = "transport-https"; | ||
1345 | plugin->protocol = "https"; | ||
1346 | #else | ||
1347 | plugin->name = "transport-http"; | ||
1348 | plugin->protocol = "http"; | ||
1349 | #endif | ||
1350 | /* Configure plugin from configuration */ | ||
1351 | res = configure_plugin (plugin); | ||
1352 | if (res == GNUNET_SYSERR) | ||
1353 | { | ||
1354 | GNUNET_free_non_null (plugin->server_addr_v4); | ||
1355 | GNUNET_free_non_null (plugin->server_addr_v6); | ||
1356 | GNUNET_free (plugin); | ||
1357 | GNUNET_free (api); | ||
1358 | return NULL; | ||
1359 | } | ||
1360 | |||
1361 | /* checking IPv6 support */ | ||
1362 | http_check_ipv6 (plugin); | ||
1363 | |||
1364 | /* Start client */ | ||
1365 | res = client_start (plugin); | ||
1366 | if (res == GNUNET_SYSERR) | ||
1367 | { | ||
1368 | GNUNET_free_non_null (plugin->server_addr_v4); | ||
1369 | GNUNET_free_non_null (plugin->server_addr_v6); | ||
1370 | GNUNET_free (plugin); | ||
1371 | GNUNET_free (api); | ||
1372 | return NULL; | ||
1373 | } | ||
1374 | |||
1375 | /* Start server */ | ||
1376 | if (plugin->client_only == GNUNET_NO) | ||
1377 | { | ||
1378 | res = server_start (plugin); | ||
1379 | if (res == GNUNET_SYSERR) | ||
1380 | { | ||
1381 | server_stop (plugin); | ||
1382 | client_stop (plugin); | ||
1383 | |||
1384 | GNUNET_free_non_null (plugin->server_addr_v4); | ||
1385 | GNUNET_free_non_null (plugin->server_addr_v6); | ||
1386 | GNUNET_free (plugin); | ||
1387 | GNUNET_free (api); | ||
1388 | return NULL; | ||
1389 | } | ||
1390 | } | ||
1391 | /* Report addresses to transport service */ | ||
1392 | start_report_addresses (plugin); | ||
1393 | |||
1394 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1395 | "Plugin `%s' loaded\n", plugin->name); | ||
1396 | return api; | ||
1397 | } | ||
1398 | |||
1399 | |||
1400 | /** | ||
1401 | * Exit point from the plugin. | ||
1402 | */ | ||
1403 | void * | ||
1404 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) | ||
1405 | { | ||
1406 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; | ||
1407 | struct Plugin *plugin = api->cls; | ||
1408 | struct Session *s; | ||
1409 | struct Session *next; | ||
1410 | |||
1411 | if (NULL == plugin) | ||
1412 | { | ||
1413 | GNUNET_free (api); | ||
1414 | return NULL; | ||
1415 | } | ||
1416 | |||
1417 | if (GNUNET_SCHEDULER_NO_TASK != plugin->notify_ext_task) | ||
1418 | { | ||
1419 | GNUNET_SCHEDULER_cancel (plugin->notify_ext_task); | ||
1420 | plugin->notify_ext_task = GNUNET_SCHEDULER_NO_TASK; | ||
1421 | } | ||
1422 | |||
1423 | if (NULL != plugin->ext_addr) | ||
1424 | { | ||
1425 | plugin->env->notify_address (plugin->env->cls, GNUNET_NO, plugin->ext_addr, plugin->ext_addr_len, "http"); | ||
1426 | GNUNET_free (plugin->ext_addr); | ||
1427 | } | ||
1428 | |||
1429 | /* Stop reporting addresses to transport service */ | ||
1430 | stop_report_addresses (plugin); | ||
1431 | |||
1432 | /* cleaning up sessions */ | ||
1433 | s = plugin->head; | ||
1434 | while (s != NULL) | ||
1435 | { | ||
1436 | next = s->next; | ||
1437 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1438 | "Disconnecting `%s' \n", GNUNET_i2s (&s->target)); | ||
1439 | if (s->inbound == GNUNET_NO) | ||
1440 | GNUNET_assert (GNUNET_OK == client_disconnect (s)); | ||
1441 | else | ||
1442 | GNUNET_assert (GNUNET_OK == server_disconnect (s)); | ||
1443 | s = next; | ||
1444 | } | ||
1445 | |||
1446 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping server\n"); | ||
1447 | /* Stop server */ | ||
1448 | server_stop (plugin); | ||
1449 | |||
1450 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping client\n"); | ||
1451 | /* Stop client */ | ||
1452 | client_stop (plugin); | ||
1453 | |||
1454 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1455 | "Plugin `%s' unloaded\n", plugin->name); | ||
1456 | GNUNET_free_non_null (plugin->server_addr_v4); | ||
1457 | GNUNET_free_non_null (plugin->server_addr_v6); | ||
1458 | GNUNET_free_non_null (plugin->external_hostname); | ||
1459 | GNUNET_free (plugin); | ||
1460 | GNUNET_free (api); | ||
1461 | return NULL; | ||
1462 | } | ||
1463 | |||
1464 | /* end of plugin_transport_http.c */ | ||