aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/transport/plugin_transport_http_server.c1728
-rw-r--r--src/transport/test_transport_api_http_reverse_peer1.conf2
-rw-r--r--src/transport/test_transport_api_http_reverse_peer2.conf2
-rw-r--r--src/transport/transport-testing.c4
-rw-r--r--src/transport/transport.conf.in12
5 files changed, 888 insertions, 860 deletions
diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c
index aba4b5ed0..0db5e31c5 100644
--- a/src/transport/plugin_transport_http_server.c
+++ b/src/transport/plugin_transport_http_server.c
@@ -54,242 +54,247 @@
54 54
55 55
56/** 56/**
57 * Session handle for connections. 57 * Information we keep with MHD for an HTTP request.
58 */ 58 */
59struct Session 59struct ServerConnection
60{ 60{
61 /** 61 /**
62 * Stored in a linked list. 62 * The session this server connection belongs to
63 */ 63 */
64 struct Session *next; 64 struct Session *session;
65 65
66 /** 66 /**
67 * Stored in a linked list. 67 * The MHD connection
68 */ 68 */
69 struct Session *prev; 69 struct MHD_Connection *mhd_conn;
70 70
71 /** 71 /**
72 * To whom are we talking to (set to our identity 72 * The MHD daemon
73 * if we are still waiting for the welcome message)
74 */ 73 */
75 struct GNUNET_PeerIdentity target; 74 struct MHD_Daemon *mhd_daemon;
76 75
77 /** 76 /**
78 * Pointer to the global plugin struct. 77 * Options requested by peer
79 */ 78 */
80 struct HTTP_Server_Plugin *plugin; 79 uint32_t options;
80#define OPTION_LONG_POLL 1 /* GET request wants long-poll semantics */
81 81
82 /** 82 /**
83 * next pointer for double linked list 83 * _RECV or _SEND
84 */ 84 */
85 struct HTTP_Message *msg_head; 85 int direction;
86 86
87 /** 87 /**
88 * previous pointer for double linked list 88 * For PUT connections: Is this the first or last callback with size 0
89 * For GET connections: Have we sent a message
89 */ 90 */
90 struct HTTP_Message *msg_tail; 91 int connected;
92
93};
91 94
95
96/**
97 * Wrapper to manage addresses
98 */
99struct HttpAddressWrapper
100{
92 /** 101 /**
93 * Message stream tokenizer for incoming data 102 * Linked list next
94 */ 103 */
95 struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk; 104 struct HttpAddressWrapper *next;
96 105
97 /** 106 /**
98 * Client recv handle 107 * Linked list previous
99 */ 108 */
100 struct ServerConnection *server_recv; 109 struct HttpAddressWrapper *prev;
101 110
102 /** 111 /**
103 * Client send handle 112 * An address we are using.
104 */ 113 */
105 struct ServerConnection *server_send; 114 struct HttpAddress *address;
106 115
107 /** 116 /**
108 * Address 117 * Length of the address.
109 */ 118 */
110 struct GNUNET_HELLO_Address *address; 119 size_t addrlen;
120};
121
111 122
123/**
124 * Message to send using http
125 */
126struct HTTP_Message
127{
112 /** 128 /**
113 * Unique HTTP/S connection tag for this connection 129 * next pointer for double linked list
114 */ 130 */
115 uint32_t tag; 131 struct HTTP_Message *next;
116 132
117 /** 133 /**
118 * ATS network type in NBO 134 * previous pointer for double linked list
119 */ 135 */
120 uint32_t ats_address_network_type; 136 struct HTTP_Message *prev;
121 137
122 /** 138 /**
123 * Was session given to transport service? 139 * buffer containing data to send
124 */ 140 */
125 int session_passed; 141 char *buf;
126 142
127 /** 143 /**
128 * Did we immediately end the session in disconnect_cb 144 * amount of data already sent
129 */ 145 */
130 int session_ended; 146 size_t pos;
131 147
132 /** 148 /**
133 * Absolute time when to receive data again 149 * buffer length
134 * Used for receive throttling
135 */ 150 */
136 struct GNUNET_TIME_Absolute next_receive; 151 size_t size;
137 152
138 /** 153 /**
139 * Session timeout task 154 * HTTP/S specific overhead
140 */ 155 */
141 GNUNET_SCHEDULER_TaskIdentifier timeout_task; 156 size_t overhead;
142 157
143 /** 158 /**
144 * Should this session get disconnected? GNUNET_YES/NO 159 * Continuation function to call once the transmission buffer
160 * has again space available. NULL if there is no
161 * continuation to call.
162 */
163 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
164
165 /**
166 * Closure for transmit_cont.
145 */ 167 */
146 int disconnect; 168 void *transmit_cont_cls;
147}; 169};
148 170
149 171
150struct ServerConnection 172/**
173 * Session handle for connections.
174 */
175struct Session
151{ 176{
152 /**
153 * _RECV or _SEND
154 */
155 int direction;
156 177
157 /** 178 /**
158 * For PUT connections: Is this the first or last callback with size 0 179 * To whom are we talking to (set to our identity
159 * For GET connections: Have we sent a message 180 * if we are still waiting for the welcome message)
160 */ 181 */
161 int connected; 182 struct GNUNET_PeerIdentity target;
162 183
163 /** 184 /**
164 * The session this server connection belongs to 185 * Pointer to the global plugin struct.
165 */ 186 */
166 struct Session *session; 187 struct HTTP_Server_Plugin *plugin;
167 188
168 /** 189 /**
169 * The MHD connection 190 * next pointer for double linked list
170 */ 191 */
171 struct MHD_Connection *mhd_conn; 192 struct HTTP_Message *msg_head;
172 193
173 /** 194 /**
174 * The MHD daemon 195 * previous pointer for double linked list
175 */ 196 */
176 struct MHD_Daemon *mhd_daemon; 197 struct HTTP_Message *msg_tail;
177 198
178 /** 199 /**
179 * Options requested by peer 200 * Message stream tokenizer for incoming data
180 */ 201 */
181 uint32_t options; 202 struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk;
182#define OPTION_LONG_POLL 1 /* GET request wants long-poll semantics */
183};
184
185 203
186/**
187 * Encapsulation of all of the state of the plugin.
188 */
189struct HTTP_Server_Plugin
190{
191 /** 204 /**
192 * Our environment. 205 * Client recv handle
193 */ 206 */
194 struct GNUNET_TRANSPORT_PluginEnvironment *env; 207 struct ServerConnection *server_recv;
195 208
196 /** 209 /**
197 * Linked list head of open sessions. 210 * Client send handle
198 */ 211 */
199 struct Session *head; 212 struct ServerConnection *server_send;
200 213
201 /** 214 /**
202 * Linked list tail of open sessions. 215 * Address
203 */ 216 */
204 struct Session *tail; 217 struct GNUNET_HELLO_Address *address;
205 218
206 /** 219 /**
207 * Plugin name 220 * Absolute time when to receive data again
221 * Used for receive throttling
208 */ 222 */
209 char *name; 223 struct GNUNET_TIME_Absolute next_receive;
210 224
211 /** 225 /**
212 * Protocol 226 * Session timeout task
213 */ 227 */
214 char *protocol; 228 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
215 229
216 /** 230 /**
217 * My options to be included in the address 231 * Unique HTTP/S connection tag for this connection
218 */ 232 */
219 uint32_t options; 233 uint32_t tag;
220 234
221 /** 235 /**
222 * External address 236 * ATS network type in NBO
223 */ 237 */
224 char *external_hostname; 238 uint32_t ats_address_network_type;
225 239
226 /** 240 /**
227 * Verify external address 241 * #GNUNET_YES if this session is known to the service.
228 */ 242 */
229 int verify_external_hostname; 243 int known_to_service;
230 244
231 /** 245};
232 * Maximum number of sockets the plugin can use
233 * Each http inbound /outbound connections are two connections
234 */
235 unsigned int max_connections;
236 246
237 /**
238 * Current number of sockets the plugin can use
239 * Each http inbound /outbound connections are two connections
240 */
241 unsigned int cur_connections;
242 247
248/**
249 * Encapsulation of all of the state of the plugin.
250 */
251struct HTTP_Server_Plugin
252{
243 /** 253 /**
244 * Did we immediately end the session in disconnect_cb 254 * Our environment.
245 */ 255 */
246 int in_shutdown; 256 struct GNUNET_TRANSPORT_PluginEnvironment *env;
247 257
248 /** 258 /**
249 * Length of peer id 259 * Hash map of open sessions.
250 */ 260 */
251 int peer_id_length; 261 struct GNUNET_CONTAINER_MultiPeerMap *sessions;
252 262
253 /** 263 /**
254 * External hostname the plugin can be connected to, can be different to 264 * Function to call about session status changes.
255 * the host's FQDN, used e.g. for reverse proxying
256 */ 265 */
257 struct GNUNET_HELLO_Address *ext_addr; 266 GNUNET_TRANSPORT_SessionInfoCallback sic;
258 267
259 /** 268 /**
260 * Notify transport only about external address 269 * Closure for @e sic.
261 */ 270 */
262 unsigned int external_only; 271 void *sic_cls;
263 272
264 /** 273 /**
265 * use IPv6 274 * Plugin name
266 */ 275 */
267 uint16_t use_ipv6; 276 char *name;
268 277
269 /** 278 /**
270 * use IPv4 279 * Protocol
271 */ 280 */
272 uint16_t use_ipv4; 281 char *protocol;
273 282
274 /** 283 /**
275 * Port used 284 * External address
276 */ 285 */
277 uint16_t port; 286 char *external_hostname;
278 287
279 /** 288 /**
280 * Task calling transport service about external address 289 * External hostname the plugin can be connected to, can be different to
290 * the host's FQDN, used e.g. for reverse proxying
281 */ 291 */
282 GNUNET_SCHEDULER_TaskIdentifier notify_ext_task; 292 struct GNUNET_HELLO_Address *ext_addr;
283 293
284 /** 294 /**
285 * NAT handle & address management 295 * NAT handle & address management
286 */ 296 */
287 struct GNUNET_NAT_Handle *nat; 297 struct GNUNET_NAT_Handle *nat;
288
289 /**
290 * List of own addresses
291 */
292
293 /** 298 /**
294 * IPv4 addresses DLL head 299 * IPv4 addresses DLL head
295 */ 300 */
@@ -311,26 +316,6 @@ struct HTTP_Server_Plugin
311 struct sockaddr_in6 *server_addr_v6; 316 struct sockaddr_in6 *server_addr_v6;
312 317
313 /** 318 /**
314 * MHD IPv4 task
315 */
316 GNUNET_SCHEDULER_TaskIdentifier server_v4_task;
317
318 /**
319 * MHD IPv6 task
320 */
321 GNUNET_SCHEDULER_TaskIdentifier server_v6_task;
322
323 /**
324 * The IPv4 server is scheduled to run asap
325 */
326 int server_v4_immediately;
327
328 /**
329 * The IPv6 server is scheduled to run asap
330 */
331 int server_v6_immediately;
332
333 /**
334 * MHD IPv4 daemon 319 * MHD IPv4 daemon
335 */ 320 */
336 struct MHD_Daemon *server_v4; 321 struct MHD_Daemon *server_v4;
@@ -340,11 +325,6 @@ struct HTTP_Server_Plugin
340 */ 325 */
341 struct MHD_Daemon *server_v6; 326 struct MHD_Daemon *server_v6;
342 327
343 /**
344 * Regex for parsing URLs
345 */
346 regex_t url_regex;
347
348#if BUILD_HTTPS 328#if BUILD_HTTPS
349 /** 329 /**
350 * Crypto related 330 * Crypto related
@@ -368,105 +348,224 @@ struct HTTP_Server_Plugin
368 char *cert; 348 char *cert;
369#endif 349#endif
370 350
371}; 351 /**
352 * MHD IPv4 task
353 */
354 GNUNET_SCHEDULER_TaskIdentifier server_v4_task;
372 355
356 /**
357 * MHD IPv6 task
358 */
359 GNUNET_SCHEDULER_TaskIdentifier server_v6_task;
373 360
374/**
375 * Wrapper to manage addresses
376 */
377struct HttpAddressWrapper
378{
379 /** 361 /**
380 * Linked list next 362 * Task calling transport service about external address
381 */ 363 */
382 struct HttpAddressWrapper *next; 364 GNUNET_SCHEDULER_TaskIdentifier notify_ext_task;
383 365
384 /** 366 /**
385 * Linked list previous 367 * Notify transport only about external address
386 */ 368 */
387 struct HttpAddressWrapper *prev; 369 unsigned int external_only;
388 370
389 struct HttpAddress *address; 371 /**
372 * The IPv4 server is scheduled to run asap
373 */
374 int server_v4_immediately;
390 375
391 size_t addrlen; 376 /**
392}; 377 * The IPv6 server is scheduled to run asap
378 */
379 int server_v6_immediately;
393 380
381 /**
382 * Verify external address
383 */
384 int verify_external_hostname;
394 385
395/**
396 * Message to send using http
397 */
398struct HTTP_Message
399{
400 /** 386 /**
401 * next pointer for double linked list 387 * Maximum number of sockets the plugin can use
388 * Each http inbound /outbound connections are two connections
402 */ 389 */
403 struct HTTP_Message *next; 390 unsigned int max_connections;
404 391
405 /** 392 /**
406 * previous pointer for double linked list 393 * Current number of sockets the plugin can use
394 * Each http inbound /outbound connections are two connections
407 */ 395 */
408 struct HTTP_Message *prev; 396 unsigned int cur_connections;
409 397
410 /** 398 /**
411 * buffer containing data to send 399 * Did we immediately end the session in disconnect_cb
412 */ 400 */
413 char *buf; 401 int in_shutdown;
414 402
415 /** 403 /**
416 * amount of data already sent 404 * Length of peer id
417 */ 405 */
418 size_t pos; 406 int peer_id_length;
419 407
420 /** 408 /**
421 * buffer length 409 * My options to be included in the address
422 */ 410 */
423 size_t size; 411 uint32_t options;
424 412
425 /** 413 /**
426 * HTTP/S specific overhead 414 * use IPv6
427 */ 415 */
428 size_t overhead; 416 uint16_t use_ipv6;
429 417
430 /** 418 /**
431 * Continuation function to call once the transmission buffer 419 * use IPv4
432 * has again space available. NULL if there is no
433 * continuation to call.
434 */ 420 */
435 GNUNET_TRANSPORT_TransmitContinuation transmit_cont; 421 uint16_t use_ipv4;
436 422
437 /** 423 /**
438 * Closure for transmit_cont. 424 * Port used
439 */ 425 */
440 void *transmit_cont_cls; 426 uint16_t port;
427
428 /**
429 * Regex for parsing URLs. FIXME: this seems overkill.
430 */
431 regex_t url_regex;
432
441}; 433};
442 434
443 435
444/** 436/**
445 * Start session timeout for session s 437 * If a session monitor is attached, notify it about the new
446 * @param s the session 438 * session state.
439 *
440 * @param plugin our plugin
441 * @param session session that changed state
442 * @param state new state of the session
447 */ 443 */
448static void 444static void
449server_start_session_timeout (struct Session *s); 445notify_session_monitor (struct HTTP_Server_Plugin *plugin,
446 struct Session *session,
447 enum GNUNET_TRANSPORT_SessionState state)
448{
449 struct GNUNET_TRANSPORT_SessionInfo info;
450
451 if (NULL == plugin->sic)
452 return;
453 memset (&info, 0, sizeof (info));
454 info.state = state;
455 info.is_inbound = GNUNET_YES;
456 // info.num_msg_pending = session->msgs_in_queue; // FIXME
457 // info.num_bytes_pending = session->bytes_in_queue; // FIXME
458 // info.receive_delay = session->next_receive; // FIXME
459 // info.session_timeout = session->timeout; // FIXME
460 info.address = session->address;
461 plugin->sic (plugin->sic_cls,
462 session,
463 &info);
464}
450 465
451 466
452/** 467/**
453 * Increment session timeout due to activity for session s 468 * Reschedule the execution of both IPv4 and IPv6 server.
454 * @param s the session 469 *
470 * @param plugin the plugin
471 * @param server which server to schedule v4 or v6?
472 * @param now #GNUNET_YES to schedule execution immediately, #GNUNET_NO to wait
473 * until timeout
455 */ 474 */
456static void 475static void
457server_reschedule_session_timeout (struct Session *s); 476server_reschedule (struct HTTP_Server_Plugin *plugin,
477 struct MHD_Daemon *server,
478 int now);
458 479
459 480
460/** 481/**
461 * Cancel timeout for session s 482 * Deletes the session. Must not be used afterwards.
462 * @param s the session 483 *
484 * @param s the session to delete
463 */ 485 */
464static void 486static void
465server_stop_session_timeout (struct Session *s); 487server_delete_session (struct Session *s)
488{
489 struct HTTP_Server_Plugin *plugin = s->plugin;
490 struct HTTP_Message *msg;
491 struct HTTP_Message *tmp;
492 struct ServerConnection *send;
493 struct ServerConnection *recv;
494
495 if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task)
496 {
497 GNUNET_SCHEDULER_cancel (s->timeout_task);
498 s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
499 }
500 GNUNET_assert (GNUNET_OK ==
501 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
502 &s->target,
503 s));
504 msg = s->msg_head;
505 while (NULL != msg)
506 {
507 tmp = msg->next;
508 GNUNET_CONTAINER_DLL_remove (s->msg_head,
509 s->msg_tail,
510 msg);
511 if (NULL != msg->transmit_cont)
512 msg->transmit_cont (msg->transmit_cont_cls,
513 &s->target,
514 GNUNET_SYSERR,
515 msg->size,
516 msg->pos + msg->overhead);
517 GNUNET_free (msg);
518 msg = tmp;
519 }
520 send = s->server_send;
521 if (NULL != send)
522 {
523 LOG (GNUNET_ERROR_TYPE_DEBUG,
524 "Server: %p / %p Terminating inbound PUT session to peer `%s'\n",
525 s, send,
526 GNUNET_i2s (&s->target));
527 send->session = NULL;
528 MHD_set_connection_option (send->mhd_conn,
529 MHD_CONNECTION_OPTION_TIMEOUT,
530 1 /* 0 = no timeout, so this is MIN */);
531 server_reschedule (plugin,
532 send->mhd_daemon,
533 GNUNET_YES);
534 }
535 recv = s->server_recv;
536 if (NULL != recv)
537 {
538 LOG (GNUNET_ERROR_TYPE_DEBUG,
539 "Server: %p / %p Terminating inbound GET session to peer `%s'\n",
540 s, recv, GNUNET_i2s (&s->target));
541 recv->session = NULL;
542 MHD_set_connection_option (recv->mhd_conn,
543 MHD_CONNECTION_OPTION_TIMEOUT,
544 1 /* 0 = no timeout, so this is MIN */);
545 server_reschedule (plugin,
546 recv->mhd_daemon,
547 GNUNET_YES);
548 }
549 if (GNUNET_YES == s->known_to_service)
550 plugin->env->session_end (plugin->env->cls,
551 s->address,
552 s);
553 if (NULL != s->msg_tk)
554 {
555 GNUNET_SERVER_mst_destroy (s->msg_tk);
556 s->msg_tk = NULL;
557 }
558 GNUNET_HELLO_address_free (s->address);
559 LOG (GNUNET_ERROR_TYPE_DEBUG,
560 "Session %p destroyed\n",
561 s);
562 GNUNET_free (s);
563}
466 564
467 565
468/** 566/**
469 * Disconnect session @a s 567 * Disconnect session @a s by telling MHD to close the
568 * connections (reducing timeout, etc.).
470 * 569 *
471 * @param cls closure with the `struct HTTP_Server_Plugin` 570 * @param cls closure with the `struct HTTP_Server_Plugin`
472 * @param s the session 571 * @param s the session
@@ -474,31 +573,54 @@ server_stop_session_timeout (struct Session *s);
474 */ 573 */
475static int 574static int
476http_server_plugin_disconnect_session (void *cls, 575http_server_plugin_disconnect_session (void *cls,
477 struct Session *s); 576 struct Session *s)
577{
578 server_delete_session (s);
579 return GNUNET_OK;
580}
478 581
479 582
480/** 583/**
481 * Does session s exist? 584 * Session was idle, so disconnect it
482 * 585 *
483 * @param plugin the plugin handle 586 * @param cls the session
484 * @param s the session 587 * @param tc task context
485 * @return #GNUNET_YES on success, #GNUNET_NO on error
486 */ 588 */
487static int 589static void
488server_exist_session (struct HTTP_Server_Plugin *plugin, struct Session *s); 590server_session_timeout (void *cls,
591 const struct GNUNET_SCHEDULER_TaskContext *tc)
592{
593 struct Session *s = cls;
594
595 s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
596 GNUNET_log (TIMEOUT_LOG,
597 "Session %p was idle for %s, disconnecting\n",
598 s,
599 GNUNET_STRINGS_relative_time_to_string (HTTP_SERVER_SESSION_TIMEOUT,
600 GNUNET_YES));
601 server_delete_session (s);
602}
489 603
490 604
491/** 605/**
492 * Reschedule the execution of both IPv4 and IPv6 server 606 * Increment session timeout due to activity session @a s
493 * @param plugin the plugin 607 *
494 * @param server which server to schedule v4 or v6? 608 * @param s the session
495 * @param now #GNUNET_YES to schedule execution immediately, #GNUNET_NO to wait
496 * until timeout
497 */ 609 */
498static void 610static void
499server_reschedule (struct HTTP_Server_Plugin *plugin, 611server_reschedule_session_timeout (struct Session *s)
500 struct MHD_Daemon *server, 612{
501 int now); 613 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
614 GNUNET_SCHEDULER_cancel (s->timeout_task);
615 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT,
616 &server_session_timeout,
617 s);
618 GNUNET_log (TIMEOUT_LOG,
619 "Timeout rescheduled for session %p set to %s\n",
620 s,
621 GNUNET_STRINGS_relative_time_to_string (HTTP_SERVER_SESSION_TIMEOUT,
622 GNUNET_YES));
623}
502 624
503 625
504/** 626/**
@@ -530,29 +652,19 @@ server_reschedule (struct HTTP_Server_Plugin *plugin,
530 */ 652 */
531static ssize_t 653static ssize_t
532http_server_plugin_send (void *cls, 654http_server_plugin_send (void *cls,
533 struct Session *session, 655 struct Session *session,
534 const char *msgbuf, size_t msgbuf_size, 656 const char *msgbuf,
535 unsigned int priority, 657 size_t msgbuf_size,
536 struct GNUNET_TIME_Relative to, 658 unsigned int priority,
537 GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) 659 struct GNUNET_TIME_Relative to,
660 GNUNET_TRANSPORT_TransmitContinuation cont,
661 void *cont_cls)
538{ 662{
539 struct HTTP_Server_Plugin *plugin = cls; 663 struct HTTP_Server_Plugin *plugin = cls;
540 struct HTTP_Message *msg; 664 struct HTTP_Message *msg;
541 int bytes_sent = 0; 665 ssize_t bytes_sent = 0;
542 char *stat_txt; 666 char *stat_txt;
543 667
544 GNUNET_assert (plugin != NULL);
545 GNUNET_assert (session != NULL);
546
547 if (GNUNET_NO == server_exist_session (plugin, session))
548 {
549 GNUNET_break (0);
550 return GNUNET_SYSERR;
551 }
552 if (session->disconnect)
553 return GNUNET_SYSERR;
554
555
556 LOG (GNUNET_ERROR_TYPE_DEBUG, 668 LOG (GNUNET_ERROR_TYPE_DEBUG,
557 "Session %p/connection %p: Sending message with %u to peer `%s'\n", 669 "Session %p/connection %p: Sending message with %u to peer `%s'\n",
558 session, 670 session,
@@ -570,25 +682,45 @@ http_server_plugin_send (void *cls,
570 msg->transmit_cont = cont; 682 msg->transmit_cont = cont;
571 msg->transmit_cont_cls = cont_cls; 683 msg->transmit_cont_cls = cont_cls;
572 memcpy (msg->buf, msgbuf, msgbuf_size); 684 memcpy (msg->buf, msgbuf, msgbuf_size);
573 685 GNUNET_CONTAINER_DLL_insert_tail (session->msg_head,
574 GNUNET_CONTAINER_DLL_insert_tail (session->msg_head, session->msg_tail, msg); 686 session->msg_tail,
575 687 msg);
576 GNUNET_asprintf (&stat_txt, "# bytes currently in %s_server buffers", plugin->protocol); 688 GNUNET_asprintf (&stat_txt,
689 "# bytes currently in %s_server buffers",
690 plugin->protocol);
577 GNUNET_STATISTICS_update (plugin->env->stats, 691 GNUNET_STATISTICS_update (plugin->env->stats,
578 stat_txt, msgbuf_size, GNUNET_NO); 692 stat_txt, msgbuf_size, GNUNET_NO);
579 GNUNET_free (stat_txt); 693 GNUNET_free (stat_txt);
580 694
581 if (NULL != session->server_send) 695 if (NULL != session->server_send)
582 {
583 server_reschedule (session->plugin, 696 server_reschedule (session->plugin,
584 session->server_send->mhd_daemon, 697 session->server_send->mhd_daemon,
585 GNUNET_YES); 698 GNUNET_YES);
586 }
587 return bytes_sent; 699 return bytes_sent;
588} 700}
589 701
590 702
591/** 703/**
704 * Terminate session.
705 *
706 * @param cls the `struct HTTP_Server_Plugin *`
707 * @param peer for which this is a session
708 * @param value the `struct Session` to clean up
709 * @return #GNUNET_OK (continue to iterate)
710 */
711static int
712destroy_session_cb (void *cls,
713 const struct GNUNET_PeerIdentity *peer,
714 void *value)
715{
716 struct Session *s = value;
717
718 server_delete_session (s);
719 return GNUNET_OK;
720}
721
722
723/**
592 * Function that can be used to force the plugin to disconnect 724 * Function that can be used to force the plugin to disconnect
593 * from the given peer and cancel all previous transmissions 725 * from the given peer and cancel all previous transmissions
594 * (and their continuationc). 726 * (and their continuationc).
@@ -601,24 +733,14 @@ http_server_plugin_disconnect_peer (void *cls,
601 const struct GNUNET_PeerIdentity *target) 733 const struct GNUNET_PeerIdentity *target)
602{ 734{
603 struct HTTP_Server_Plugin *plugin = cls; 735 struct HTTP_Server_Plugin *plugin = cls;
604 struct Session *next;
605 struct Session *pos;
606 736
607 LOG (GNUNET_ERROR_TYPE_DEBUG, 737 LOG (GNUNET_ERROR_TYPE_DEBUG,
608 "Transport tells me to disconnect `%s'\n", 738 "Transport tells me to disconnect `%s'\n",
609 GNUNET_i2s (target)); 739 GNUNET_i2s (target));
610 next = plugin->head; 740 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
611 while (NULL != (pos = next)) 741 target,
612 { 742 &destroy_session_cb,
613 next = pos->next; 743 plugin);
614 if (0 == memcmp (target, &pos->target, sizeof (struct GNUNET_PeerIdentity)))
615 {
616 LOG (GNUNET_ERROR_TYPE_DEBUG,
617 "Disconnecting session %p to `%s'\n",
618 pos, GNUNET_i2s (target));
619 http_server_plugin_disconnect_session (plugin, pos);
620 }
621 }
622} 744}
623 745
624 746
@@ -671,9 +793,9 @@ http_server_plugin_address_suggested (void *cls,
671 793
672/** 794/**
673 * Creates a new outbound session the transport 795 * Creates a new outbound session the transport
674 * service will use to send data to the peer 796 * service will use to send data to the peer.
675 * 797 *
676 * Since HTTP/S server cannot create sessions, always return NULL 798 * Since HTTP/S server cannot create sessions, always returns NULL.
677 * 799 *
678 * @param cls the plugin 800 * @param cls the plugin
679 * @param address the address 801 * @param address the address
@@ -688,85 +810,155 @@ http_server_plugin_get_session (void *cls,
688 810
689 811
690/** 812/**
691 * Deleting the session 813 * Call MHD IPv4 to process pending requests and then go back
692 * Must not be used afterwards 814 * and schedule the next run.
693 * 815 *
694 * @param cls closure with the `struct HTTP_ServerPlugin` 816 * @param cls plugin as closure
695 * @param s the session to delete 817 * @param tc task context
696 * @return #GNUNET_OK on success
697 */ 818 */
698static int 819static void
699server_delete_session (void *cls, 820server_v4_run (void *cls,
700 struct Session *s) 821 const struct GNUNET_SCHEDULER_TaskContext *tc)
701{ 822{
702 struct HTTP_Server_Plugin *plugin = cls; 823 struct HTTP_Server_Plugin *plugin = cls;
703 struct HTTP_Message *msg;
704 struct HTTP_Message *tmp;
705 824
706 server_stop_session_timeout(s); 825 plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
707 GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); 826 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
708 msg = s->msg_head; 827 return;
709 while (NULL != msg) 828 plugin->server_v4_immediately = GNUNET_NO;
710 { 829 GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4));
711 tmp = msg->next; 830 server_reschedule (plugin, plugin->server_v4, GNUNET_NO);
712 GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
713 if (NULL != msg->transmit_cont)
714 msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR,
715 msg->size, msg->pos + msg->overhead);
716 GNUNET_free (msg);
717 msg = tmp;
718 }
719 if (NULL != s->msg_tk)
720 {
721 GNUNET_SERVER_mst_destroy (s->msg_tk);
722 s->msg_tk = NULL;
723 }
724 GNUNET_HELLO_address_free (s->address);
725 GNUNET_free_non_null (s->server_recv);
726 GNUNET_free_non_null (s->server_send);
727 LOG (GNUNET_ERROR_TYPE_DEBUG,
728 "Session %p destroyed\n",
729 s);
730 GNUNET_free (s);
731 return GNUNET_OK;
732} 831}
733 832
734 833
735/** 834/**
736* Cancel timeout for session s 835 * Call MHD IPv6 to process pending requests and then go back
737* 836 * and schedule the next run.
738* @param s the session 837 *
739*/ 838 * @param cls plugin as closure
839 * @param tc task context
840 */
740static void 841static void
741server_stop_session_timeout (struct Session *s) 842server_v6_run (void *cls,
843 const struct GNUNET_SCHEDULER_TaskContext *tc)
742{ 844{
743 GNUNET_assert (NULL != s); 845 struct HTTP_Server_Plugin *plugin = cls;
744 846
745 if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) 847 plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
746 { 848 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
747 GNUNET_SCHEDULER_cancel (s->timeout_task); 849 return;
748 s->timeout_task = GNUNET_SCHEDULER_NO_TASK; 850 plugin->server_v6_immediately = GNUNET_NO;
749 GNUNET_log (TIMEOUT_LOG, "Timeout stopped for session %p\n", s); 851 GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6));
750 } 852 server_reschedule (plugin, plugin->server_v6, GNUNET_NO);
751} 853}
752 854
753 855
754/** 856/**
755 * Function that queries MHD's select sets and 857 * Function that queries MHD's select sets and
756 * starts the task waiting for them. 858 * starts the task waiting for them.
859 *
757 * @param plugin plugin 860 * @param plugin plugin
758 * @param daemon_handle the MHD daemon handle 861 * @param daemon_handle the MHD daemon handle
759 * @param now schedule immediately 862 * @return gnunet task identifier
760 * @return task identifier
761 */ 863 */
762static GNUNET_SCHEDULER_TaskIdentifier 864static GNUNET_SCHEDULER_TaskIdentifier
763server_schedule (struct HTTP_Server_Plugin *plugin, 865server_schedule (struct HTTP_Server_Plugin *plugin,
764 struct MHD_Daemon *daemon_handle, 866 struct MHD_Daemon *daemon_handle,
765 int now); 867 int now)
868{
869 GNUNET_SCHEDULER_TaskIdentifier ret;
870 fd_set rs;
871 fd_set ws;
872 fd_set es;
873 struct GNUNET_NETWORK_FDSet *wrs;
874 struct GNUNET_NETWORK_FDSet *wws;
875 int max;
876 MHD_UNSIGNED_LONG_LONG timeout;
877 static unsigned long long last_timeout = 0;
878 int haveto;
879 struct GNUNET_TIME_Relative tv;
880
881 if (GNUNET_YES == plugin->in_shutdown)
882 return GNUNET_SCHEDULER_NO_TASK;
883
884 ret = GNUNET_SCHEDULER_NO_TASK;
885 FD_ZERO (&rs);
886 FD_ZERO (&ws);
887 FD_ZERO (&es);
888 wrs = GNUNET_NETWORK_fdset_create ();
889 wws = GNUNET_NETWORK_fdset_create ();
890 max = -1;
891 GNUNET_assert (MHD_YES ==
892 MHD_get_fdset (daemon_handle,
893 &rs,
894 &ws,
895 &es,
896 &max));
897 haveto = MHD_get_timeout (daemon_handle, &timeout);
898 if (haveto == MHD_YES)
899 {
900 if (timeout != last_timeout)
901 {
902 LOG (GNUNET_ERROR_TYPE_DEBUG,
903 "SELECT Timeout changed from %llu to %llu (ms)\n",
904 last_timeout, timeout);
905 last_timeout = timeout;
906 }
907 if (timeout <= GNUNET_TIME_UNIT_SECONDS.rel_value_us / 1000LL)
908 tv.rel_value_us = (uint64_t) timeout * 1000LL;
909 else
910 tv = GNUNET_TIME_UNIT_SECONDS;
911 }
912 else
913 tv = GNUNET_TIME_UNIT_SECONDS;
914 /* Force immediate run, since we have outbound data to send */
915 if (now == GNUNET_YES)
916 tv = GNUNET_TIME_UNIT_MILLISECONDS;
917 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
918 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
919
920 if (daemon_handle == plugin->server_v4)
921 {
922 if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK)
923 {
924 GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
925 plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
926 }
927#if 0
928 LOG (GNUNET_ERROR_TYPE_DEBUG,
929 "Scheduling IPv4 server task in %llu ms\n",
930 tv);
931#endif
932 ret =
933 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
934 tv, wrs, wws,
935 &server_v4_run, plugin);
936 }
937 if (daemon_handle == plugin->server_v6)
938 {
939 if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK)
940 {
941 GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
942 plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
943 }
944#if 0
945 LOG (GNUNET_ERROR_TYPE_DEBUG,
946 "Scheduling IPv6 server task in %llu ms\n", tv);
947#endif
948 ret =
949 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
950 tv, wrs, wws,
951 &server_v6_run, plugin);
952 }
953 GNUNET_NETWORK_fdset_destroy (wrs);
954 GNUNET_NETWORK_fdset_destroy (wws);
955 return ret;
956}
766 957
767 958
768/** 959/**
769 * Reschedule the execution of both IPv4 and IPv6 server 960 * Reschedule the execution of both IPv4 and IPv6 server
961 *
770 * @param plugin the plugin 962 * @param plugin the plugin
771 * @param server which server to schedule v4 or v6? 963 * @param server which server to schedule v4 or v6?
772 * @param now #GNUNET_YES to schedule execution immediately, #GNUNET_NO to wait 964 * @param now #GNUNET_YES to schedule execution immediately, #GNUNET_NO to wait
@@ -812,55 +1004,6 @@ server_reschedule (struct HTTP_Server_Plugin *plugin,
812 1004
813 1005
814/** 1006/**
815 * Disconnect session @a s
816 *
817 * @param cls closure with the `struct HTTP_Server_Plugin`
818 * @param s the session
819 * @return #GNUNET_OK on success
820 */
821static int
822http_server_plugin_disconnect_session (void *cls,
823 struct Session *s)
824{
825 struct HTTP_Server_Plugin *plugin = cls;
826 struct ServerConnection * send;
827 struct ServerConnection * recv;
828
829 if (GNUNET_NO == server_exist_session (plugin, s))
830 {
831 GNUNET_break (0);
832 return GNUNET_SYSERR;
833 }
834 s->disconnect = GNUNET_YES;
835 send = (struct ServerConnection *) s->server_send;
836 if (send != NULL)
837 {
838 LOG (GNUNET_ERROR_TYPE_DEBUG,
839 "Server: %p / %p Terminating inbound PUT session to peer `%s'\n",
840 s, send, GNUNET_i2s (&s->target));
841
842 MHD_set_connection_option (send->mhd_conn,
843 MHD_CONNECTION_OPTION_TIMEOUT,
844 1);
845 server_reschedule (s->plugin, send->mhd_daemon, GNUNET_YES);
846 }
847
848 recv = (struct ServerConnection *) s->server_recv;
849 if (recv != NULL)
850 {
851 LOG (GNUNET_ERROR_TYPE_DEBUG,
852 "Server: %p / %p Terminating inbound GET session to peer `%s'\n",
853 s, recv, GNUNET_i2s (&s->target));
854 MHD_set_connection_option (recv->mhd_conn,
855 MHD_CONNECTION_OPTION_TIMEOUT,
856 1);
857 server_reschedule (s->plugin, recv->mhd_daemon, GNUNET_YES);
858 }
859 return GNUNET_OK;
860}
861
862
863/**
864 * Function that is called to get the keepalive factor. 1007 * Function that is called to get the keepalive factor.
865 * GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to 1008 * GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
866 * calculate the interval between keepalive packets. 1009 * calculate the interval between keepalive packets.
@@ -874,16 +1017,12 @@ http_server_query_keepalive_factor (void *cls)
874 return 3; 1017 return 3;
875} 1018}
876 1019
1020
877static void 1021static void
878http_server_plugin_update_session_timeout (void *cls, 1022http_server_plugin_update_session_timeout (void *cls,
879 const struct GNUNET_PeerIdentity *peer, 1023 const struct GNUNET_PeerIdentity *peer,
880 struct Session *session) 1024 struct Session *session)
881{ 1025{
882 struct HTTP_Server_Plugin *plugin = cls;
883
884 if (GNUNET_NO == server_exist_session (plugin, session))
885 return;
886
887 server_reschedule_session_timeout (session); 1026 server_reschedule_session_timeout (session);
888} 1027}
889 1028
@@ -900,7 +1039,7 @@ server_mhd_connection_timeout (struct HTTP_Server_Plugin *plugin,
900 struct Session *s, 1039 struct Session *s,
901 unsigned int to) 1040 unsigned int to)
902{ 1041{
903 /* Setting timeouts for other connections */ 1042 /* Setting timeouts for other connections */
904 if (NULL != s->server_recv) 1043 if (NULL != s->server_recv)
905 { 1044 {
906 LOG (GNUNET_ERROR_TYPE_DEBUG, 1045 LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -1054,6 +1193,48 @@ server_parse_url (struct HTTP_Server_Plugin *plugin,
1054 1193
1055 1194
1056/** 1195/**
1196 * Closure for #session_tag_it().
1197 */
1198struct SessionTagContext
1199{
1200 /**
1201 * Set to session matching the tag.
1202 */
1203 struct Session *res;
1204
1205 /**
1206 * Tag we are looking for.
1207 */
1208 uint32_t tag;
1209};
1210
1211
1212/**
1213 * Find a session with a matching tag.
1214 *
1215 * @param cls the `struct SessionTagContext *`
1216 * @param key peer identity (unused)
1217 * @param value the `struct Session *`
1218 * @return #GNUNET_NO if we found the session, #GNUNET_OK if not
1219 */
1220static int
1221session_tag_it (void *cls,
1222 const struct GNUNET_PeerIdentity *key,
1223 void *value)
1224{
1225 struct SessionTagContext *stc = cls;
1226 struct Session *s = value;
1227
1228 if (s->tag == stc->tag)
1229 {
1230 stc->res = s;
1231 return GNUNET_NO;
1232 }
1233 return GNUNET_YES;
1234}
1235
1236
1237/**
1057 * Lookup a mhd connection and create one if none is found 1238 * Lookup a mhd connection and create one if none is found
1058 * 1239 *
1059 * @param plugin the plugin handle 1240 * @param plugin the plugin handle
@@ -1064,18 +1245,18 @@ server_parse_url (struct HTTP_Server_Plugin *plugin,
1064 */ 1245 */
1065static struct ServerConnection * 1246static struct ServerConnection *
1066server_lookup_connection (struct HTTP_Server_Plugin *plugin, 1247server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1067 struct MHD_Connection *mhd_connection, const char *url, 1248 struct MHD_Connection *mhd_connection,
1068 const char *method) 1249 const char *url,
1250 const char *method)
1069{ 1251{
1070 struct Session *s = NULL; 1252 struct Session *s = NULL;
1071 struct ServerConnection *sc = NULL; 1253 struct ServerConnection *sc = NULL;
1072 const union MHD_ConnectionInfo *conn_info; 1254 const union MHD_ConnectionInfo *conn_info;
1073 struct HttpAddress *addr; 1255 struct HttpAddress *addr;
1074
1075 struct GNUNET_ATS_Information ats; 1256 struct GNUNET_ATS_Information ats;
1076 struct GNUNET_PeerIdentity target; 1257 struct GNUNET_PeerIdentity target;
1077 size_t addr_len; 1258 size_t addr_len;
1078 uint32_t tag = 0; 1259 struct SessionTagContext stc;
1079 uint32_t options; 1260 uint32_t options;
1080 int direction = GNUNET_SYSERR; 1261 int direction = GNUNET_SYSERR;
1081 unsigned int to; 1262 unsigned int to;
@@ -1089,8 +1270,9 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1089 "New %s connection from %s\n", 1270 "New %s connection from %s\n",
1090 method, 1271 method,
1091 url); 1272 url);
1092 1273 stc.tag = 0;
1093 if (GNUNET_SYSERR == server_parse_url (plugin, url, &target, &tag, &options)) 1274 if (GNUNET_SYSERR ==
1275 server_parse_url (plugin, url, &target, &stc.tag, &options))
1094 { 1276 {
1095 LOG (GNUNET_ERROR_TYPE_DEBUG, 1277 LOG (GNUNET_ERROR_TYPE_DEBUG,
1096 "Invalid url %s\n", url); 1278 "Invalid url %s\n", url);
@@ -1112,51 +1294,38 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1112 LOG (GNUNET_ERROR_TYPE_DEBUG, 1294 LOG (GNUNET_ERROR_TYPE_DEBUG,
1113 "New %s connection from %s with tag %u (%u of %u)\n", 1295 "New %s connection from %s with tag %u (%u of %u)\n",
1114 method, 1296 method,
1115 GNUNET_i2s (&target), tag, 1297 GNUNET_i2s (&target),
1298 stc.tag,
1116 plugin->cur_connections, plugin->max_connections); 1299 plugin->cur_connections, plugin->max_connections);
1117 /* find duplicate session */ 1300 /* find existing session */
1118 s = plugin->head; 1301 stc.res = NULL;
1119 while (s != NULL) 1302 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
1120 { 1303 &target,
1121 if ((0 == memcmp (&s->target, &target, sizeof (struct GNUNET_PeerIdentity))) && 1304 &session_tag_it,
1122 (s->tag == tag)) 1305 &stc);
1123 break; 1306 if (NULL == (s = stc.res))
1124 s = s->next;
1125 }
1126 if (s != NULL)
1127 {
1128 if ((_RECEIVE == direction) && (NULL != s->server_recv))
1129 {
1130 LOG (GNUNET_ERROR_TYPE_DEBUG,
1131 "Duplicate PUT connection from `%s' tag %u, dismissing new connection\n",
1132 GNUNET_i2s (&target),
1133 tag);
1134 return NULL;
1135 }
1136 if ((_SEND == direction) && (NULL != s->server_send))
1137 {
1138 LOG (GNUNET_ERROR_TYPE_DEBUG,
1139 "Duplicate GET connection from `%s' tag %u, dismissing new connection\n",
1140 GNUNET_i2s (&target),
1141 tag);
1142 return NULL;
1143 }
1144 }
1145 else
1146 { 1307 {
1147 /* create new session */ 1308 /* create new session */
1148 addr = NULL; 1309 addr = NULL;
1149 switch (conn_info->client_addr->sa_family) 1310 switch (conn_info->client_addr->sa_family)
1150 { 1311 {
1151 case (AF_INET): 1312 case (AF_INET):
1152 addr = http_common_address_from_socket (plugin->protocol, conn_info->client_addr, sizeof (struct sockaddr_in)); 1313 addr = http_common_address_from_socket (plugin->protocol,
1314 conn_info->client_addr,
1315 sizeof (struct sockaddr_in));
1153 addr_len = http_common_address_get_size (addr); 1316 addr_len = http_common_address_get_size (addr);
1154 ats = plugin->env->get_address_type (plugin->env->cls, conn_info->client_addr, sizeof (struct sockaddr_in)); 1317 ats = plugin->env->get_address_type (plugin->env->cls,
1318 conn_info->client_addr,
1319 sizeof (struct sockaddr_in));
1155 break; 1320 break;
1156 case (AF_INET6): 1321 case (AF_INET6):
1157 addr = http_common_address_from_socket (plugin->protocol, conn_info->client_addr, sizeof (struct sockaddr_in6)); 1322 addr = http_common_address_from_socket (plugin->protocol,
1323 conn_info->client_addr,
1324 sizeof (struct sockaddr_in6));
1158 addr_len = http_common_address_get_size (addr); 1325 addr_len = http_common_address_get_size (addr);
1159 ats = plugin->env->get_address_type (plugin->env->cls, conn_info->client_addr, sizeof (struct sockaddr_in6)); 1326 ats = plugin->env->get_address_type (plugin->env->cls,
1327 conn_info->client_addr,
1328 sizeof (struct sockaddr_in6));
1160 break; 1329 break;
1161 default: 1330 default:
1162 /* external host name */ 1331 /* external host name */
@@ -1164,21 +1333,24 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1164 ats.type = htonl (GNUNET_ATS_NET_WAN); 1333 ats.type = htonl (GNUNET_ATS_NET_WAN);
1165 return NULL; 1334 return NULL;
1166 } 1335 }
1167
1168 s = GNUNET_new (struct Session); 1336 s = GNUNET_new (struct Session);
1169 memcpy (&s->target, &target, sizeof (struct GNUNET_PeerIdentity)); 1337 s->target = target;
1170 s->plugin = plugin; 1338 s->plugin = plugin;
1171 s->address = GNUNET_HELLO_address_allocate (&s->target, PLUGIN_NAME, 1339 s->address = GNUNET_HELLO_address_allocate (&s->target,
1172 addr, addr_len, GNUNET_HELLO_ADDRESS_INFO_INBOUND); 1340 PLUGIN_NAME,
1341 addr,
1342 addr_len,
1343 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1173 s->ats_address_network_type = ats.value; 1344 s->ats_address_network_type = ats.value;
1174 s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS; 1345 s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS;
1175 s->tag = tag; 1346 s->tag = stc.tag;
1176 s->server_recv = NULL; 1347 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT,
1177 s->server_send = NULL; 1348 &server_session_timeout,
1178 s->session_passed = GNUNET_NO; 1349 s);
1179 s->session_ended = GNUNET_NO; 1350 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
1180 server_start_session_timeout(s); 1351 &s->target,
1181 GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); 1352 s,
1353 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1182 1354
1183 LOG (GNUNET_ERROR_TYPE_DEBUG, 1355 LOG (GNUNET_ERROR_TYPE_DEBUG,
1184 "Creating new session %p for peer `%s' connecting from `%s'\n", 1356 "Creating new session %p for peer `%s' connecting from `%s'\n",
@@ -1188,6 +1360,23 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1188 addr_len)); 1360 addr_len));
1189 GNUNET_free_non_null (addr); 1361 GNUNET_free_non_null (addr);
1190 } 1362 }
1363
1364 if ( (_RECEIVE == direction) && (NULL != s->server_recv) )
1365 {
1366 LOG (GNUNET_ERROR_TYPE_DEBUG,
1367 "Duplicate PUT connection from `%s' tag %u, dismissing new connection\n",
1368 GNUNET_i2s (&target),
1369 stc.tag);
1370 return NULL;
1371 }
1372 if ((_SEND == direction) && (NULL != s->server_send))
1373 {
1374 LOG (GNUNET_ERROR_TYPE_DEBUG,
1375 "Duplicate GET connection from `%s' tag %u, dismissing new connection\n",
1376 GNUNET_i2s (&target),
1377 stc.tag);
1378 return NULL;
1379 }
1191 sc = GNUNET_new (struct ServerConnection); 1380 sc = GNUNET_new (struct ServerConnection);
1192 if (conn_info->client_addr->sa_family == AF_INET) 1381 if (conn_info->client_addr->sa_family == AF_INET)
1193 sc->mhd_daemon = plugin->server_v4; 1382 sc->mhd_daemon = plugin->server_v4;
@@ -1205,6 +1394,7 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1205 1394
1206 if ((NULL != s->server_send) && (NULL != s->server_recv)) 1395 if ((NULL != s->server_send) && (NULL != s->server_recv))
1207 { 1396 {
1397 s->known_to_service = GNUNET_YES;
1208 plugin->env->session_start (NULL, s->address ,s, NULL, 0); 1398 plugin->env->session_start (NULL, s->address ,s, NULL, 0);
1209 } 1399 }
1210 1400
@@ -1223,7 +1413,6 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1223 to = (HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL); 1413 to = (HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL);
1224 server_mhd_connection_timeout (plugin, s, to); 1414 server_mhd_connection_timeout (plugin, s, to);
1225 } 1415 }
1226
1227 LOG (GNUNET_ERROR_TYPE_DEBUG, 1416 LOG (GNUNET_ERROR_TYPE_DEBUG,
1228 "Setting timeout for %p to %u sec.\n", sc, to); 1417 "Setting timeout for %p to %u sec.\n", sc, to);
1229 return sc; 1418 return sc;
@@ -1231,39 +1420,6 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1231 1420
1232 1421
1233/** 1422/**
1234 * Lookup a session for a server connection
1235 *
1236 * @param plugin the plugin
1237 * @param sc the server connection
1238 * @return the session found or NULL
1239 */
1240static struct Session *
1241server_lookup_session (struct HTTP_Server_Plugin *plugin,
1242 struct ServerConnection * sc)
1243{
1244 struct Session *s;
1245
1246 for (s = plugin->head; NULL != s; s = s->next)
1247 if ((s->server_recv == sc) || (s->server_send == sc))
1248 return s;
1249 return NULL;
1250}
1251
1252
1253static int
1254server_exist_session (struct HTTP_Server_Plugin *plugin,
1255 struct Session *s)
1256{
1257 struct Session * head;
1258
1259 for (head = plugin->head; head != NULL; head = head->next)
1260 if (head == s)
1261 return GNUNET_YES;
1262 return GNUNET_NO;
1263}
1264
1265
1266/**
1267 * Callback called by MHD when it needs data to send 1423 * Callback called by MHD when it needs data to send
1268 * 1424 *
1269 * @param cls current session 1425 * @param cls current session
@@ -1273,7 +1429,10 @@ server_exist_session (struct HTTP_Server_Plugin *plugin,
1273 * @return bytes written to buffer 1429 * @return bytes written to buffer
1274 */ 1430 */
1275static ssize_t 1431static ssize_t
1276server_send_callback (void *cls, uint64_t pos, char *buf, size_t max) 1432server_send_callback (void *cls,
1433 uint64_t pos,
1434 char *buf,
1435 size_t max)
1277{ 1436{
1278 struct Session *s = cls; 1437 struct Session *s = cls;
1279 struct ServerConnection *sc; 1438 struct ServerConnection *sc;
@@ -1281,8 +1440,6 @@ server_send_callback (void *cls, uint64_t pos, char *buf, size_t max)
1281 struct HTTP_Message *msg; 1440 struct HTTP_Message *msg;
1282 char *stat_txt; 1441 char *stat_txt;
1283 1442
1284 if (GNUNET_NO == server_exist_session (s->plugin, s))
1285 return 0;
1286 sc = s->server_send; 1443 sc = s->server_send;
1287 if (NULL == sc) 1444 if (NULL == sc)
1288 return 0; 1445 return 0;
@@ -1298,7 +1455,9 @@ server_send_callback (void *cls, uint64_t pos, char *buf, size_t max)
1298 /* removing message */ 1455 /* removing message */
1299 if (msg->pos == msg->size) 1456 if (msg->pos == msg->size)
1300 { 1457 {
1301 GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); 1458 GNUNET_CONTAINER_DLL_remove (s->msg_head,
1459 s->msg_tail,
1460 msg);
1302 if (NULL != msg->transmit_cont) 1461 if (NULL != msg->transmit_cont)
1303 msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK, 1462 msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK,
1304 msg->size, msg->size + msg->overhead); 1463 msg->size, msg->size + msg->overhead);
@@ -1342,7 +1501,8 @@ server_send_callback (void *cls, uint64_t pos, char *buf, size_t max)
1342 * @return #GNUNET_OK 1501 * @return #GNUNET_OK
1343 */ 1502 */
1344static int 1503static int
1345server_receive_mst_cb (void *cls, void *client, 1504server_receive_mst_cb (void *cls,
1505 void *client,
1346 const struct GNUNET_MessageHeader *message) 1506 const struct GNUNET_MessageHeader *message)
1347{ 1507{
1348 struct Session *s = cls; 1508 struct Session *s = cls;
@@ -1351,24 +1511,30 @@ server_receive_mst_cb (void *cls, void *client,
1351 struct GNUNET_TIME_Relative delay; 1511 struct GNUNET_TIME_Relative delay;
1352 char *stat_txt; 1512 char *stat_txt;
1353 1513
1354 if (GNUNET_NO == server_exist_session (s->plugin, s))
1355 return GNUNET_OK;
1356
1357
1358 atsi.type = htonl (GNUNET_ATS_NETWORK_TYPE); 1514 atsi.type = htonl (GNUNET_ATS_NETWORK_TYPE);
1359 atsi.value = s->ats_address_network_type; 1515 atsi.value = s->ats_address_network_type;
1360 GNUNET_break (s->ats_address_network_type != ntohl (GNUNET_ATS_NET_UNSPECIFIED)); 1516 GNUNET_break (s->ats_address_network_type !=
1361 1517 ntohl (GNUNET_ATS_NET_UNSPECIFIED));
1362 delay = plugin->env->receive (plugin->env->cls, s->address, s, message); 1518
1363 plugin->env->update_address_metrics (plugin->env->cls, s->address, s, &atsi, 1); 1519 if (GNUNET_NO == s->known_to_service)
1364 1520 {
1365 GNUNET_asprintf (&stat_txt, "# bytes received via %s_server", plugin->protocol); 1521 s->known_to_service = GNUNET_YES;
1522 plugin->env->session_start (NULL, s->address, s, NULL, 0);
1523 }
1524 delay = plugin->env->receive (plugin->env->cls,
1525 s->address,
1526 s,
1527 message);
1528 plugin->env->update_address_metrics (plugin->env->cls,
1529 s->address, s,
1530 &atsi, 1);
1531 GNUNET_asprintf (&stat_txt,
1532 "# bytes received via %s_server",
1533 plugin->protocol);
1366 GNUNET_STATISTICS_update (plugin->env->stats, 1534 GNUNET_STATISTICS_update (plugin->env->stats,
1367 stat_txt, ntohs (message->size), GNUNET_NO); 1535 stat_txt, ntohs (message->size), GNUNET_NO);
1368 GNUNET_free (stat_txt); 1536 GNUNET_free (stat_txt);
1369 1537 s->next_receive = GNUNET_TIME_relative_to_absolute (delay);
1370 s->session_passed = GNUNET_YES;
1371 s->next_receive = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay);
1372 if (delay.rel_value_us > 0) 1538 if (delay.rel_value_us > 0)
1373 { 1539 {
1374 LOG (GNUNET_ERROR_TYPE_DEBUG, 1540 LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -1384,6 +1550,7 @@ server_receive_mst_cb (void *cls, void *client,
1384 return GNUNET_OK; 1550 return GNUNET_OK;
1385} 1551}
1386 1552
1553
1387/** 1554/**
1388 * Add headers to a request indicating that we allow Cross-Origin Resource 1555 * Add headers to a request indicating that we allow Cross-Origin Resource
1389 * Sharing. 1556 * Sharing.
@@ -1402,6 +1569,7 @@ add_cors_headers(struct MHD_Response *response)
1402 "86400"); 1569 "86400");
1403} 1570}
1404 1571
1572
1405/** 1573/**
1406 * MHD callback for a new incoming connection 1574 * MHD callback for a new incoming connection
1407 * 1575 *
@@ -1416,26 +1584,31 @@ add_cors_headers(struct MHD_Response *response)
1416 * @return MHD_YES if connection is accepted, MHD_NO on reject 1584 * @return MHD_YES if connection is accepted, MHD_NO on reject
1417 */ 1585 */
1418static int 1586static int
1419server_access_cb (void *cls, struct MHD_Connection *mhd_connection, 1587server_access_cb (void *cls,
1420 const char *url, const char *method, const char *version, 1588 struct MHD_Connection *mhd_connection,
1421 const char *upload_data, size_t * upload_data_size, 1589 const char *url,
1590 const char *method,
1591 const char *version,
1592 const char *upload_data,
1593 size_t *upload_data_size,
1422 void **httpSessionCache) 1594 void **httpSessionCache)
1423{ 1595{
1424 struct HTTP_Server_Plugin *plugin = cls; 1596 struct HTTP_Server_Plugin *plugin = cls;
1425 int res = MHD_YES;
1426
1427 struct ServerConnection *sc = *httpSessionCache; 1597 struct ServerConnection *sc = *httpSessionCache;
1428 struct Session *s; 1598 struct Session *s;
1429 struct MHD_Response *response; 1599 struct MHD_Response *response;
1600 int res = MHD_YES;
1430 1601
1431 LOG (GNUNET_ERROR_TYPE_DEBUG, 1602 LOG (GNUNET_ERROR_TYPE_DEBUG,
1432 _("Access from connection %p (%u of %u) for `%s' `%s' url `%s' with upload data size %u\n"), 1603 _("Access from connection %p (%u of %u) for `%s' `%s' url `%s' with upload data size %u\n"),
1433 sc, 1604 sc,
1434 plugin->cur_connections, plugin->max_connections, 1605 plugin->cur_connections,
1435 method, version, url, (*upload_data_size)); 1606 plugin->max_connections,
1436 1607 method,
1437 GNUNET_assert (cls != NULL); 1608 version,
1438 if (sc == NULL) 1609 url,
1610 (*upload_data_size));
1611 if (NULL == sc)
1439 { 1612 {
1440 /* CORS pre-flight request */ 1613 /* CORS pre-flight request */
1441 if (0 == strcmp (MHD_HTTP_METHOD_OPTIONS, method)) 1614 if (0 == strcmp (MHD_HTTP_METHOD_OPTIONS, method))
@@ -1449,13 +1622,18 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection,
1449 } 1622 }
1450 /* new connection */ 1623 /* new connection */
1451 sc = server_lookup_connection (plugin, mhd_connection, url, method); 1624 sc = server_lookup_connection (plugin, mhd_connection, url, method);
1452 if (sc != NULL) 1625 if (NULL != sc)
1453 { 1626 {
1627 /* attach to new / existing session */
1454 (*httpSessionCache) = sc; 1628 (*httpSessionCache) = sc;
1455 } 1629 }
1456 else 1630 else
1457 { 1631 {
1458 response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE), HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO); 1632 /* existing session already has matching connection, refuse */
1633 response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),
1634 HTTP_ERROR_RESPONSE,
1635 MHD_NO,
1636 MHD_NO);
1459 MHD_add_response_header (response, 1637 MHD_add_response_header (response,
1460 MHD_HTTP_HEADER_CONTENT_TYPE, 1638 MHD_HTTP_HEADER_CONTENT_TYPE,
1461 "text/html"); 1639 "text/html");
@@ -1465,33 +1643,19 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection,
1465 return res; 1643 return res;
1466 } 1644 }
1467 } 1645 }
1468 else 1646 /* 'old' connection */
1647 if (NULL == (s = sc->session))
1469 { 1648 {
1470 /* 'old' connection */ 1649 /* Session was already disconnected;
1471 if (NULL == server_lookup_session (plugin, sc)) 1650 sent HTTP/1.1: 200 OK as response */
1472 {
1473 /* Session was already disconnected */
1474 return MHD_NO;
1475 }
1476 }
1477
1478 /* existing connection */
1479 sc = (*httpSessionCache);
1480 s = sc->session;
1481 GNUNET_assert (NULL != s);
1482 /* connection is to be disconnected */
1483 if (s->disconnect == GNUNET_YES)
1484 {
1485 /* Sent HTTP/1.1: 200 OK as response */
1486 response = MHD_create_response_from_data (strlen ("Thank you!"), 1651 response = MHD_create_response_from_data (strlen ("Thank you!"),
1487 "Thank you!", 1652 "Thank you!",
1488 MHD_NO, MHD_NO); 1653 MHD_NO, MHD_NO);
1489 add_cors_headers(response); 1654 add_cors_headers(response);
1490 MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); 1655 MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1491 MHD_destroy_response (response); 1656 MHD_destroy_response (response);
1492 return MHD_YES; 1657 return MHD_YES;
1493 } 1658 }
1494 GNUNET_assert (s != NULL);
1495 1659
1496 if (sc->direction == _SEND) 1660 if (sc->direction == _SEND)
1497 { 1661 {
@@ -1595,68 +1759,61 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection,
1595 * @param httpSessionCache the pointer to distinguish 1759 * @param httpSessionCache the pointer to distinguish
1596 */ 1760 */
1597static void 1761static void
1598server_disconnect_cb (void *cls, struct MHD_Connection *connection, 1762server_disconnect_cb (void *cls,
1763 struct MHD_Connection *connection,
1599 void **httpSessionCache) 1764 void **httpSessionCache)
1600{ 1765{
1601 struct HTTP_Server_Plugin *plugin = cls; 1766 struct HTTP_Server_Plugin *plugin = cls;
1602 struct ServerConnection *sc = *httpSessionCache; 1767 struct ServerConnection *sc = *httpSessionCache;
1603 struct Session *s; 1768 struct Session *s;
1604 struct Session *t;
1605 1769
1606 LOG (GNUNET_ERROR_TYPE_DEBUG, 1770 LOG (GNUNET_ERROR_TYPE_DEBUG,
1607 "Disconnect for connection %p\n", 1771 "Disconnect for connection %p\n",
1608 sc); 1772 sc);
1609 if (sc == NULL) 1773 if (NULL == sc)
1610 return; 1774 return; /* never really got setup */
1611 1775 if (NULL == (s = sc->session))
1612 if (NULL == (s = server_lookup_session (plugin, sc))) 1776 return; /* session already dead */
1613 return;
1614 for (t = plugin->head; t != NULL; t = t->next)
1615 if (t == s)
1616 break;
1617 if (NULL == t)
1618 return;
1619
1620 if (sc->direction == _SEND) 1777 if (sc->direction == _SEND)
1621 { 1778 {
1622 LOG (GNUNET_ERROR_TYPE_DEBUG, 1779 LOG (GNUNET_ERROR_TYPE_DEBUG,
1623 "Peer `%s' connection %p, GET on address `%s' disconnected\n", 1780 "Peer `%s' connection %p, GET on address `%s' disconnected\n",
1624 GNUNET_i2s (&s->target), s->server_send, 1781 GNUNET_i2s (&s->target),
1782 s->server_send,
1625 http_common_plugin_address_to_string (plugin->protocol, 1783 http_common_plugin_address_to_string (plugin->protocol,
1626 s->address->address, 1784 s->address->address,
1627 s->address->address_length)); 1785 s->address->address_length));
1628 s->server_send = NULL; 1786 s->server_send = NULL;
1629 if (!(sc->options & OPTION_LONG_POLL) && NULL != (s->server_recv)) 1787 if (! ( (0 != (sc->options & OPTION_LONG_POLL)) &&
1788 (NULL != s->server_recv) ) )
1630 { 1789 {
1631 s->disconnect = GNUNET_YES; 1790 server_delete_session (s);
1632 GNUNET_assert (NULL != s->server_recv->mhd_conn); 1791 GNUNET_free (sc);
1633#if MHD_VERSION >= 0x00090E00 1792 plugin->cur_connections--;
1634 MHD_set_connection_option (s->server_recv->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, 1793 return;
1635 1);
1636#endif
1637 server_reschedule (plugin, s->server_recv->mhd_daemon, GNUNET_NO);
1638 } 1794 }
1639 } 1795 }
1640 if (sc->direction == _RECEIVE) 1796 if (sc->direction == _RECEIVE)
1641 { 1797 {
1642 LOG (GNUNET_ERROR_TYPE_DEBUG, 1798 LOG (GNUNET_ERROR_TYPE_DEBUG,
1643 "Peer `%s' connection %p PUT on address `%s' disconnected\n", 1799 "Peer `%s' connection %p PUT on address `%s' disconnected\n",
1644 GNUNET_i2s (&s->target), s->server_recv, 1800 GNUNET_i2s (&s->target),
1801 s->server_recv,
1645 http_common_plugin_address_to_string (plugin->protocol, 1802 http_common_plugin_address_to_string (plugin->protocol,
1646 s->address->address, 1803 s->address->address,
1647 s->address->address_length)); 1804 s->address->address_length));
1648 s->server_recv = NULL; 1805 s->server_recv = NULL;
1649 if (s->msg_tk != NULL) 1806 if (NULL != s->msg_tk)
1650 { 1807 {
1651 GNUNET_SERVER_mst_destroy (s->msg_tk); 1808 GNUNET_SERVER_mst_destroy (s->msg_tk);
1652 s->msg_tk = NULL; 1809 s->msg_tk = NULL;
1653 } 1810 }
1654 } 1811 }
1655
1656 GNUNET_free (sc); 1812 GNUNET_free (sc);
1657 plugin->cur_connections--; 1813 plugin->cur_connections--;
1658 1814
1659 if (s->disconnect && (s->server_send == NULL) && (s->server_recv == NULL)) 1815 if ( (NULL == s->server_send) &&
1816 (NULL == s->server_recv) )
1660 { 1817 {
1661 LOG (GNUNET_ERROR_TYPE_DEBUG, 1818 LOG (GNUNET_ERROR_TYPE_DEBUG,
1662 "Peer `%s' on address `%s' disconnected\n", 1819 "Peer `%s' on address `%s' disconnected\n",
@@ -1665,13 +1822,7 @@ server_disconnect_cb (void *cls, struct MHD_Connection *connection,
1665 s->address->address, 1822 s->address->address,
1666 s->address->address_length)); 1823 s->address->address_length));
1667 1824
1668 if ((GNUNET_YES == s->session_passed) && (GNUNET_NO == s->session_ended)) 1825 server_delete_session (s);
1669 {
1670 /* Notify transport immediately that this session is invalid */
1671 s->session_ended = GNUNET_YES;
1672 plugin->env->session_end (plugin->env->cls, s->address, s);
1673 }
1674 server_delete_session (plugin, s);
1675 } 1826 }
1676} 1827}
1677 1828
@@ -1685,7 +1836,9 @@ server_disconnect_cb (void *cls, struct MHD_Connection *connection,
1685 * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected 1836 * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected
1686 */ 1837 */
1687static int 1838static int
1688server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len) 1839server_accept_cb (void *cls,
1840 const struct sockaddr *addr,
1841 socklen_t addr_len)
1689{ 1842{
1690 struct HTTP_Server_Plugin *plugin = cls; 1843 struct HTTP_Server_Plugin *plugin = cls;
1691 1844
@@ -1708,167 +1861,17 @@ server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len)
1708 1861
1709 1862
1710static void 1863static void
1711server_log (void *arg, const char *fmt, va_list ap) 1864server_log (void *arg,
1865 const char *fmt,
1866 va_list ap)
1712{ 1867{
1713 char text[1024]; 1868 char text[1024];
1714 1869
1715 vsnprintf (text, sizeof (text), fmt, ap); 1870 vsnprintf (text, sizeof (text), fmt, ap);
1716 va_end (ap); 1871 va_end (ap);
1717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server: %s\n", text); 1872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1718} 1873 "Server: %s\n",
1719 1874 text);
1720
1721/**
1722 * Call MHD IPv4 to process pending requests and then go back
1723 * and schedule the next run.
1724 * @param cls plugin as closure
1725 * @param tc task context
1726 */
1727static void
1728server_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1729{
1730 struct HTTP_Server_Plugin *plugin = cls;
1731
1732 GNUNET_assert (cls != NULL);
1733
1734 plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
1735 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1736 return;
1737#if 0
1738 LOG (GNUNET_ERROR_TYPE_DEBUG,
1739 "Running IPv4 server\n");
1740#endif
1741 plugin->server_v4_immediately = GNUNET_NO;
1742 GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4));
1743 server_reschedule (plugin, plugin->server_v4, GNUNET_NO);
1744}
1745
1746
1747/**
1748 * Call MHD IPv6 to process pending requests and then go back
1749 * and schedule the next run.
1750 * @param cls plugin as closure
1751 * @param tc task context
1752 */
1753static void
1754server_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1755{
1756 struct HTTP_Server_Plugin *plugin = cls;
1757
1758 GNUNET_assert (cls != NULL);
1759 plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
1760 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1761 return;
1762#if 0
1763 LOG (GNUNET_ERROR_TYPE_DEBUG,
1764 "Running IPv6 server\n");
1765#endif
1766 plugin->server_v6_immediately = GNUNET_NO;
1767 GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6));
1768 server_reschedule (plugin, plugin->server_v6, GNUNET_NO);
1769}
1770
1771
1772/**
1773 * Function that queries MHD's select sets and
1774 * starts the task waiting for them.
1775 *
1776 * @param plugin plugin
1777 * @param daemon_handle the MHD daemon handle
1778 * @return gnunet task identifier
1779 */
1780static GNUNET_SCHEDULER_TaskIdentifier
1781server_schedule (struct HTTP_Server_Plugin *plugin,
1782 struct MHD_Daemon *daemon_handle,
1783 int now)
1784{
1785 GNUNET_SCHEDULER_TaskIdentifier ret;
1786 fd_set rs;
1787 fd_set ws;
1788 fd_set es;
1789 struct GNUNET_NETWORK_FDSet *wrs;
1790 struct GNUNET_NETWORK_FDSet *wws;
1791 struct GNUNET_NETWORK_FDSet *wes;
1792 int max;
1793 MHD_UNSIGNED_LONG_LONG timeout;
1794 static unsigned long long last_timeout = 0;
1795 int haveto;
1796
1797 struct GNUNET_TIME_Relative tv;
1798
1799 if (GNUNET_YES == plugin->in_shutdown)
1800 return GNUNET_SCHEDULER_NO_TASK;
1801
1802 ret = GNUNET_SCHEDULER_NO_TASK;
1803 FD_ZERO (&rs);
1804 FD_ZERO (&ws);
1805 FD_ZERO (&es);
1806 wrs = GNUNET_NETWORK_fdset_create ();
1807 wes = GNUNET_NETWORK_fdset_create ();
1808 wws = GNUNET_NETWORK_fdset_create ();
1809 max = -1;
1810 GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max));
1811 haveto = MHD_get_timeout (daemon_handle, &timeout);
1812 if (haveto == MHD_YES)
1813 {
1814 if (timeout != last_timeout)
1815 {
1816 LOG (GNUNET_ERROR_TYPE_DEBUG,
1817 "SELECT Timeout changed from %llu to %llu (ms)\n",
1818 last_timeout, timeout);
1819 last_timeout = timeout;
1820 }
1821 if (timeout <= GNUNET_TIME_UNIT_SECONDS.rel_value_us / 1000LL)
1822 tv.rel_value_us = (uint64_t) timeout * 1000LL;
1823 else
1824 tv = GNUNET_TIME_UNIT_SECONDS;
1825 }
1826 else
1827 tv = GNUNET_TIME_UNIT_SECONDS;
1828 /* Force immediate run, since we have outbound data to send */
1829 if (now == GNUNET_YES)
1830 tv = GNUNET_TIME_UNIT_MILLISECONDS;
1831 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
1832 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
1833 GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
1834
1835 if (daemon_handle == plugin->server_v4)
1836 {
1837 if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK)
1838 {
1839 GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
1840 plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
1841 }
1842#if 0
1843 LOG (GNUNET_ERROR_TYPE_DEBUG,
1844 "Scheduling IPv4 server task in %llu ms\n",
1845 tv);
1846#endif
1847 ret =
1848 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1849 tv, wrs, wws,
1850 &server_v4_run, plugin);
1851 }
1852 if (daemon_handle == plugin->server_v6)
1853 {
1854 if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK)
1855 {
1856 GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
1857 plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
1858 }
1859#if 0
1860 LOG (GNUNET_ERROR_TYPE_DEBUG,
1861 "Scheduling IPv6 server task in %llu ms\n", tv);
1862#endif
1863 ret =
1864 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1865 tv, wrs, wws,
1866 &server_v6_run, plugin);
1867 }
1868 GNUNET_NETWORK_fdset_destroy (wrs);
1869 GNUNET_NETWORK_fdset_destroy (wws);
1870 GNUNET_NETWORK_fdset_destroy (wes);
1871 return ret;
1872} 1875}
1873 1876
1874 1877
@@ -1927,7 +1930,8 @@ server_load_certificate (struct HTTP_Server_Plugin *plugin)
1927 1930
1928 1931
1929 if (GNUNET_OK != 1932 if (GNUNET_OK !=
1930 GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, 1933 GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg,
1934 plugin->name,
1931 "KEY_FILE", &key_file)) 1935 "KEY_FILE", &key_file))
1932 { 1936 {
1933 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1937 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
@@ -1935,7 +1939,8 @@ server_load_certificate (struct HTTP_Server_Plugin *plugin)
1935 return GNUNET_SYSERR; 1939 return GNUNET_SYSERR;
1936 } 1940 }
1937 if (GNUNET_OK != 1941 if (GNUNET_OK !=
1938 GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, 1942 GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg,
1943 plugin->name,
1939 "CERT_FILE", &cert_file)) 1944 "CERT_FILE", &cert_file))
1940 { 1945 {
1941 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1946 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
@@ -2035,7 +2040,7 @@ server_load_certificate (struct HTTP_Server_Plugin *plugin)
2035 * Start the HTTP server 2040 * Start the HTTP server
2036 * 2041 *
2037 * @param plugin the plugin handle 2042 * @param plugin the plugin handle
2038 * @return GNUNET_OK on success, GNUNET_SYSERR on failure 2043 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
2039 */ 2044 */
2040static int 2045static int
2041server_start (struct HTTP_Server_Plugin *plugin) 2046server_start (struct HTTP_Server_Plugin *plugin)
@@ -2181,7 +2186,7 @@ server_start (struct HTTP_Server_Plugin *plugin)
2181} 2186}
2182 2187
2183 2188
2184void 2189static void
2185server_stop (struct HTTP_Server_Plugin *plugin) 2190server_stop (struct HTTP_Server_Plugin *plugin)
2186{ 2191{
2187 if (plugin->server_v4 != NULL) 2192 if (plugin->server_v4 != NULL)
@@ -2223,20 +2228,24 @@ server_stop (struct HTTP_Server_Plugin *plugin)
2223 * Add an address to the server's set of addresses and notify transport 2228 * Add an address to the server's set of addresses and notify transport
2224 * 2229 *
2225 * @param cls the plugin handle 2230 * @param cls the plugin handle
2226 * @param add_remove GNUNET_YES on add, GNUNET_NO on remove 2231 * @param add_remove #GNUNET_YES on add, #GNUNET_NO on remove
2227 * @param addr the address 2232 * @param addr the address
2228 * @param addrlen address length 2233 * @param addrlen address length
2229 */ 2234 */
2230static void 2235static void
2231server_add_address (void *cls, int add_remove, const struct sockaddr *addr, 2236server_add_address (void *cls,
2232 socklen_t addrlen) 2237 int add_remove,
2238 const struct sockaddr *addr,
2239 socklen_t addrlen)
2233{ 2240{
2234 struct HTTP_Server_Plugin *plugin = cls; 2241 struct HTTP_Server_Plugin *plugin = cls;
2235 struct GNUNET_HELLO_Address *address; 2242 struct GNUNET_HELLO_Address *address;
2236 struct HttpAddressWrapper *w = NULL; 2243 struct HttpAddressWrapper *w = NULL;
2237 2244
2238 w = GNUNET_new (struct HttpAddressWrapper); 2245 w = GNUNET_new (struct HttpAddressWrapper);
2239 w->address = http_common_address_from_socket (plugin->protocol, addr, addrlen); 2246 w->address = http_common_address_from_socket (plugin->protocol,
2247 addr,
2248 addrlen);
2240 if (NULL == w->address) 2249 if (NULL == w->address)
2241 { 2250 {
2242 GNUNET_free (w); 2251 GNUNET_free (w);
@@ -2244,7 +2253,9 @@ server_add_address (void *cls, int add_remove, const struct sockaddr *addr,
2244 } 2253 }
2245 w->addrlen = http_common_address_get_size (w->address); 2254 w->addrlen = http_common_address_get_size (w->address);
2246 2255
2247 GNUNET_CONTAINER_DLL_insert(plugin->addr_head, plugin->addr_tail, w); 2256 GNUNET_CONTAINER_DLL_insert (plugin->addr_head,
2257 plugin->addr_tail,
2258 w);
2248 LOG (GNUNET_ERROR_TYPE_DEBUG, 2259 LOG (GNUNET_ERROR_TYPE_DEBUG,
2249 "Notifying transport to add address `%s'\n", 2260 "Notifying transport to add address `%s'\n",
2250 http_common_plugin_address_to_string (plugin->protocol, 2261 http_common_plugin_address_to_string (plugin->protocol,
@@ -2259,7 +2270,9 @@ server_add_address (void *cls, int add_remove, const struct sockaddr *addr,
2259 "http_client", w->address, w->addrlen, GNUNET_HELLO_ADDRESS_INFO_NONE); 2270 "http_client", w->address, w->addrlen, GNUNET_HELLO_ADDRESS_INFO_NONE);
2260#endif 2271#endif
2261 2272
2262 plugin->env->notify_address (plugin->env->cls, add_remove, address); 2273 plugin->env->notify_address (plugin->env->cls,
2274 add_remove,
2275 address);
2263 GNUNET_HELLO_address_free (address); 2276 GNUNET_HELLO_address_free (address);
2264} 2277}
2265 2278
@@ -2268,28 +2281,38 @@ server_add_address (void *cls, int add_remove, const struct sockaddr *addr,
2268 * Remove an address from the server's set of addresses and notify transport 2281 * Remove an address from the server's set of addresses and notify transport
2269 * 2282 *
2270 * @param cls the plugin handle 2283 * @param cls the plugin handle
2271 * @param add_remove GNUNET_YES on add, GNUNET_NO on remove 2284 * @param add_remove #GNUNET_YES on add, #GNUNET_NO on remove
2272 * @param addr the address 2285 * @param addr the address
2273 * @param addrlen address length 2286 * @param addrlen address length
2274 */ 2287 */
2275static void 2288static void
2276server_remove_address (void *cls, int add_remove, const struct sockaddr *addr, 2289server_remove_address (void *cls,
2277 socklen_t addrlen) 2290 int add_remove,
2291 const struct sockaddr *addr,
2292 socklen_t addrlen)
2278{ 2293{
2279 struct HTTP_Server_Plugin *plugin = cls; 2294 struct HTTP_Server_Plugin *plugin = cls;
2280 struct GNUNET_HELLO_Address *address; 2295 struct GNUNET_HELLO_Address *address;
2281 struct HttpAddressWrapper *w = plugin->addr_head; 2296 struct HttpAddressWrapper *w = plugin->addr_head;
2282 size_t saddr_len; 2297 size_t saddr_len;
2283 void * saddr = http_common_address_from_socket (plugin->protocol, addr, addrlen); 2298 void * saddr;
2299
2300 saddr = http_common_address_from_socket (plugin->protocol,
2301 addr,
2302 addrlen);
2284 if (NULL == saddr) 2303 if (NULL == saddr)
2285 return; 2304 return;
2286 saddr_len = http_common_address_get_size (saddr); 2305 saddr_len = http_common_address_get_size (saddr);
2287 2306
2288 while (NULL != w) 2307 while (NULL != w)
2289 { 2308 {
2290 if (GNUNET_YES == http_common_cmp_addresses(w->address, w->addrlen, saddr, saddr_len)) 2309 if (GNUNET_YES ==
2291 break; 2310 http_common_cmp_addresses (w->address,
2292 w = w->next; 2311 w->addrlen,
2312 saddr,
2313 saddr_len))
2314 break;
2315 w = w->next;
2293 } 2316 }
2294 GNUNET_free (saddr); 2317 GNUNET_free (saddr);
2295 2318
@@ -2301,10 +2324,9 @@ server_remove_address (void *cls, int add_remove, const struct sockaddr *addr,
2301 http_common_plugin_address_to_string (plugin->protocol, 2324 http_common_plugin_address_to_string (plugin->protocol,
2302 w->address, 2325 w->address,
2303 w->addrlen)); 2326 w->addrlen));
2304 2327 GNUNET_CONTAINER_DLL_remove (plugin->addr_head,
2305 2328 plugin->addr_tail,
2306 GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w); 2329 w);
2307
2308 /* modify our published address list */ 2330 /* modify our published address list */
2309#if BUILD_HTTPS 2331#if BUILD_HTTPS
2310 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity, 2332 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
@@ -2325,16 +2347,17 @@ server_remove_address (void *cls, int add_remove, const struct sockaddr *addr,
2325 * Our external IP address/port mapping has changed. 2347 * Our external IP address/port mapping has changed.
2326 * 2348 *
2327 * @param cls closure, the 'struct LocalAddrList' 2349 * @param cls closure, the 'struct LocalAddrList'
2328 * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean 2350 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
2329 * the previous (now invalid) one 2351 * the previous (now invalid) one
2330 * @param addr either the previous or the new public IP address 2352 * @param addr either the previous or the new public IP address
2331 * @param addrlen actual lenght of the address 2353 * @param addrlen actual lenght of the address
2332 */ 2354 */
2333static void 2355static void
2334server_nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr, 2356server_nat_port_map_callback (void *cls,
2335 socklen_t addrlen) 2357 int add_remove,
2358 const struct sockaddr *addr,
2359 socklen_t addrlen)
2336{ 2360{
2337 GNUNET_assert (cls != NULL);
2338 struct HTTP_Server_Plugin *plugin = cls; 2361 struct HTTP_Server_Plugin *plugin = cls;
2339 2362
2340 LOG (GNUNET_ERROR_TYPE_DEBUG, 2363 LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -2403,7 +2426,8 @@ static int
2403server_get_addresses (struct HTTP_Server_Plugin *plugin, 2426server_get_addresses (struct HTTP_Server_Plugin *plugin,
2404 const char *service_name, 2427 const char *service_name,
2405 const struct GNUNET_CONFIGURATION_Handle *cfg, 2428 const struct GNUNET_CONFIGURATION_Handle *cfg,
2406 struct sockaddr ***addrs, socklen_t ** addr_lens) 2429 struct sockaddr ***addrs,
2430 socklen_t ** addr_lens)
2407{ 2431{
2408 int disablev6; 2432 int disablev6;
2409 unsigned long long port; 2433 unsigned long long port;
@@ -2591,7 +2615,8 @@ server_start_report_addresses (struct HTTP_Server_Plugin *plugin)
2591 socklen_t *addrlens; 2615 socklen_t *addrlens;
2592 2616
2593 res = server_get_addresses (plugin, 2617 res = server_get_addresses (plugin,
2594 plugin->name, plugin->env->cfg, 2618 plugin->name,
2619 plugin->env->cfg,
2595 &addrs, &addrlens); 2620 &addrs, &addrlens);
2596 LOG (GNUNET_ERROR_TYPE_DEBUG, 2621 LOG (GNUNET_ERROR_TYPE_DEBUG,
2597 _("Found %u addresses to report to NAT service\n"), 2622 _("Found %u addresses to report to NAT service\n"),
@@ -2604,7 +2629,9 @@ server_start_report_addresses (struct HTTP_Server_Plugin *plugin)
2604 } 2629 }
2605 2630
2606 plugin->nat = 2631 plugin->nat =
2607 GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port, 2632 GNUNET_NAT_register (plugin->env->cfg,
2633 GNUNET_YES,
2634 plugin->port,
2608 (unsigned int) res, 2635 (unsigned int) res,
2609 (const struct sockaddr **) addrs, addrlens, 2636 (const struct sockaddr **) addrs, addrlens,
2610 &server_nat_port_map_callback, NULL, plugin); 2637 &server_nat_port_map_callback, NULL, plugin);
@@ -2627,17 +2654,21 @@ server_start_report_addresses (struct HTTP_Server_Plugin *plugin)
2627static void 2654static void
2628server_stop_report_addresses (struct HTTP_Server_Plugin *plugin) 2655server_stop_report_addresses (struct HTTP_Server_Plugin *plugin)
2629{ 2656{
2657 struct HttpAddressWrapper *w;
2658
2630 /* Stop NAT handle */ 2659 /* Stop NAT handle */
2631 if (NULL != plugin->nat) 2660 if (NULL != plugin->nat)
2661 {
2632 GNUNET_NAT_unregister (plugin->nat); 2662 GNUNET_NAT_unregister (plugin->nat);
2633 2663 plugin->nat = NULL;
2664 }
2634 /* Clean up addresses */ 2665 /* Clean up addresses */
2635 struct HttpAddressWrapper *w; 2666 while (NULL != plugin->addr_head)
2636
2637 while (plugin->addr_head != NULL)
2638 { 2667 {
2639 w = plugin->addr_head; 2668 w = plugin->addr_head;
2640 GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w); 2669 GNUNET_CONTAINER_DLL_remove (plugin->addr_head,
2670 plugin->addr_tail,
2671 w);
2641 GNUNET_free (w->address); 2672 GNUNET_free (w->address);
2642 GNUNET_free (w); 2673 GNUNET_free (w);
2643 } 2674 }
@@ -2648,7 +2679,7 @@ server_stop_report_addresses (struct HTTP_Server_Plugin *plugin)
2648 * Check if IPv6 supported on this system 2679 * Check if IPv6 supported on this system
2649 * 2680 *
2650 * @param plugin the plugin handle 2681 * @param plugin the plugin handle
2651 * @return GNUNET_YES on success, else GNUNET_NO 2682 * @return #GNUNET_YES on success, else #GNUNET_NO
2652 */ 2683 */
2653static int 2684static int
2654server_check_ipv6_support (struct HTTP_Server_Plugin *plugin) 2685server_check_ipv6_support (struct HTTP_Server_Plugin *plugin)
@@ -2689,7 +2720,8 @@ server_check_ipv6_support (struct HTTP_Server_Plugin *plugin)
2689 * @param tc task context (unused) 2720 * @param tc task context (unused)
2690 */ 2721 */
2691static void 2722static void
2692server_notify_external_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 2723server_notify_external_hostname (void *cls,
2724 const struct GNUNET_SCHEDULER_TaskContext *tc)
2693{ 2725{
2694 struct HTTP_Server_Plugin *plugin = cls; 2726 struct HTTP_Server_Plugin *plugin = cls;
2695 struct HttpAddress *ext_addr; 2727 struct HttpAddress *ext_addr;
@@ -2737,7 +2769,7 @@ server_notify_external_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskCo
2737 * Configure the plugin 2769 * Configure the plugin
2738 * 2770 *
2739 * @param plugin plugin handle 2771 * @param plugin plugin handle
2740 * @return GNUNET_OK on success, GNUNET_SYSERR on failure 2772 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
2741 */ 2773 */
2742static int 2774static int
2743server_configure_plugin (struct HTTP_Server_Plugin *plugin) 2775server_configure_plugin (struct HTTP_Server_Plugin *plugin)
@@ -2754,7 +2786,8 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin)
2754 (plugin->env->cfg, plugin->name, "USE_IPv4")) 2786 (plugin->env->cfg, plugin->name, "USE_IPv4"))
2755 { 2787 {
2756 plugin->use_ipv4 = 2788 plugin->use_ipv4 =
2757 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, 2789 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
2790 plugin->name,
2758 "USE_IPv4"); 2791 "USE_IPv4");
2759 } 2792 }
2760 else 2793 else
@@ -2768,7 +2801,8 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin)
2768 (plugin->env->cfg, plugin->name, "USE_IPv6")) 2801 (plugin->env->cfg, plugin->name, "USE_IPv6"))
2769 { 2802 {
2770 plugin->use_ipv6 = 2803 plugin->use_ipv6 =
2771 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, 2804 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
2805 plugin->name,
2772 "USE_IPv6"); 2806 "USE_IPv6");
2773 } 2807 }
2774 else 2808 else
@@ -2786,7 +2820,8 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin)
2786 2820
2787 /* Reading port number from config file */ 2821 /* Reading port number from config file */
2788 if ((GNUNET_OK != 2822 if ((GNUNET_OK !=
2789 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name, 2823 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg,
2824 plugin->name,
2790 "PORT", &port)) || (port > 65535)) 2825 "PORT", &port)) || (port > 65535))
2791 { 2826 {
2792 LOG (GNUNET_ERROR_TYPE_ERROR, 2827 LOG (GNUNET_ERROR_TYPE_ERROR,
@@ -2830,7 +2865,8 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin)
2830 2865
2831 if ((plugin->use_ipv6 == GNUNET_YES) && 2866 if ((plugin->use_ipv6 == GNUNET_YES) &&
2832 (GNUNET_YES == 2867 (GNUNET_YES ==
2833 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, 2868 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2869 plugin->name,
2834 "BINDTO6", &bind6_address))) 2870 "BINDTO6", &bind6_address)))
2835 { 2871 {
2836 LOG (GNUNET_ERROR_TYPE_DEBUG, 2872 LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -2861,84 +2897,99 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin)
2861 2897
2862 plugin->verify_external_hostname = GNUNET_NO; 2898 plugin->verify_external_hostname = GNUNET_NO;
2863#if BUILD_HTTPS 2899#if BUILD_HTTPS
2864 plugin->verify_external_hostname = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, 2900 plugin->verify_external_hostname = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
2901 plugin->name,
2865 "VERIFY_EXTERNAL_HOSTNAME"); 2902 "VERIFY_EXTERNAL_HOSTNAME");
2866 if (GNUNET_SYSERR == plugin->verify_external_hostname) 2903 if (GNUNET_SYSERR == plugin->verify_external_hostname)
2867 plugin->verify_external_hostname = GNUNET_NO; 2904 plugin->verify_external_hostname = GNUNET_NO;
2868 if (GNUNET_YES == plugin->verify_external_hostname) 2905 if (GNUNET_YES == plugin->verify_external_hostname)
2869 plugin->options |= HTTP_OPTIONS_VERIFY_CERTIFICATE; 2906 plugin->options |= HTTP_OPTIONS_VERIFY_CERTIFICATE;
2870#endif 2907#endif
2871 external_hostname_use_port = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, 2908 external_hostname_use_port = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
2909 plugin->name,
2872 "EXTERNAL_HOSTNAME_USE_PORT"); 2910 "EXTERNAL_HOSTNAME_USE_PORT");
2873 if (GNUNET_SYSERR == external_hostname_use_port) 2911 if (GNUNET_SYSERR == external_hostname_use_port)
2874 external_hostname_use_port = GNUNET_NO; 2912 external_hostname_use_port = GNUNET_NO;
2875 2913
2876 2914
2877 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, 2915 if (GNUNET_YES ==
2878 "EXTERNAL_HOSTNAME", &eh_tmp)) 2916 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2917 plugin->name,
2918 "EXTERNAL_HOSTNAME",
2919 &eh_tmp))
2879 { 2920 {
2880 char * tmp = NULL; 2921 char *tmp;
2881 char * pos = NULL; 2922 char *pos = NULL;
2882 char * pos_url = NULL; 2923 char *pos_url = NULL;
2883 2924
2884 if (NULL != strstr(eh_tmp, "://")) 2925 if (NULL != strstr(eh_tmp, "://"))
2885 { 2926 tmp = &strstr(eh_tmp, "://")[3];
2886 tmp = &strstr(eh_tmp, "://")[3]; 2927 else
2887 } 2928 tmp = eh_tmp;
2888 else
2889 tmp = eh_tmp;
2890 2929
2891 if (GNUNET_YES == external_hostname_use_port) 2930 if (GNUNET_YES == external_hostname_use_port)
2931 {
2932 if ( (strlen (tmp) > 1) && (NULL != (pos = strchr(tmp, '/'))) )
2892 { 2933 {
2893 if ( (strlen (tmp) > 1) && (NULL != (pos = strchr(tmp, '/'))) ) 2934 pos_url = pos + 1;
2894 { 2935 pos[0] = '\0';
2895 pos_url = pos + 1; 2936 GNUNET_asprintf (&plugin->external_hostname,
2896 pos[0] = '\0'; 2937 "%s:%u/%s",
2897 GNUNET_asprintf (&plugin->external_hostname, "%s:%u/%s", tmp, (uint16_t) port, (NULL == pos_url) ? "" : pos_url); 2938 tmp,
2898 } 2939 (uint16_t) port,
2899 else 2940 (NULL == pos_url) ? "" : pos_url);
2900 GNUNET_asprintf (&plugin->external_hostname, "%s:%u", tmp, (uint16_t) port);
2901 } 2941 }
2902 else 2942 else
2903 plugin->external_hostname = GNUNET_strdup (tmp); 2943 GNUNET_asprintf (&plugin->external_hostname,
2904 GNUNET_free (eh_tmp); 2944 "%s:%u",
2905 2945 tmp,
2906 LOG (GNUNET_ERROR_TYPE_INFO, 2946 (uint16_t) port);
2907 _("Using external hostname `%s'\n"), 2947 }
2908 plugin->external_hostname); 2948 else
2909 plugin->notify_ext_task = GNUNET_SCHEDULER_add_now (&server_notify_external_hostname, plugin); 2949 plugin->external_hostname = GNUNET_strdup (tmp);
2950 GNUNET_free (eh_tmp);
2910 2951
2911 /* Use only configured external hostname */ 2952 LOG (GNUNET_ERROR_TYPE_INFO,
2912 if (GNUNET_CONFIGURATION_have_value 2953 _("Using external hostname `%s'\n"),
2913 (plugin->env->cfg, plugin->name, "EXTERNAL_HOSTNAME_ONLY")) 2954 plugin->external_hostname);
2914 { 2955 plugin->notify_ext_task = GNUNET_SCHEDULER_add_now (&server_notify_external_hostname,
2915 plugin->external_only = 2956 plugin);
2916 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, 2957
2917 "EXTERNAL_HOSTNAME_ONLY"); 2958 /* Use only configured external hostname */
2918 } 2959 if (GNUNET_CONFIGURATION_have_value
2919 else 2960 (plugin->env->cfg,
2920 plugin->external_only = GNUNET_NO; 2961 plugin->name,
2962 "EXTERNAL_HOSTNAME_ONLY"))
2963 {
2964 plugin->external_only =
2965 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
2966 plugin->name,
2967 "EXTERNAL_HOSTNAME_ONLY");
2968 }
2969 else
2970 plugin->external_only = GNUNET_NO;
2921 2971
2922 if (GNUNET_YES == plugin->external_only) 2972 if (GNUNET_YES == plugin->external_only)
2923 LOG (GNUNET_ERROR_TYPE_DEBUG, 2973 LOG (GNUNET_ERROR_TYPE_DEBUG,
2924 _("Notifying transport only about hostname `%s'\n"), 2974 _("Notifying transport only about hostname `%s'\n"),
2925 plugin->external_hostname); 2975 plugin->external_hostname);
2926 } 2976 }
2927 else 2977 else
2928 LOG (GNUNET_ERROR_TYPE_DEBUG, 2978 LOG (GNUNET_ERROR_TYPE_DEBUG,
2929 "No external hostname configured\n"); 2979 "No external hostname configured\n");
2930 2980
2931 /* Optional parameters */ 2981 /* Optional parameters */
2932 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, 2982 if (GNUNET_OK !=
2933 plugin->name, 2983 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg,
2934 "MAX_CONNECTIONS", &max_connections)) 2984 plugin->name,
2985 "MAX_CONNECTIONS",
2986 &max_connections))
2935 max_connections = 128; 2987 max_connections = 128;
2936 plugin->max_connections = max_connections; 2988 plugin->max_connections = max_connections;
2937 2989
2938 LOG (GNUNET_ERROR_TYPE_DEBUG, 2990 LOG (GNUNET_ERROR_TYPE_DEBUG,
2939 _("Maximum number of connections is %u\n"), 2991 _("Maximum number of connections is %u\n"),
2940 plugin->max_connections); 2992 plugin->max_connections);
2941
2942 2993
2943 plugin->peer_id_length = strlen (GNUNET_i2s_full (plugin->env->my_identity)); 2994 plugin->peer_id_length = strlen (GNUNET_i2s_full (plugin->env->my_identity));
2944 2995
@@ -2947,74 +2998,6 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin)
2947 2998
2948 2999
2949/** 3000/**
2950 * Session was idle, so disconnect it
2951 *
2952 * @param cls the session
2953 * @param tc task context
2954 */
2955static void
2956server_session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2957{
2958 struct Session *s = cls;
2959
2960 s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2961 GNUNET_log (TIMEOUT_LOG,
2962 "Session %p was idle for %s, disconnecting\n",
2963 s,
2964 GNUNET_STRINGS_relative_time_to_string (HTTP_SERVER_SESSION_TIMEOUT,
2965 GNUNET_YES));
2966
2967 /* call session destroy function */
2968 GNUNET_assert (GNUNET_OK ==
2969 http_server_plugin_disconnect_session (s->plugin, s));
2970}
2971
2972
2973/**
2974* Start session timeout for session s
2975*
2976* @param s the session
2977*/
2978static void
2979server_start_session_timeout (struct Session *s)
2980{
2981 GNUNET_assert (NULL != s);
2982 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task);
2983 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT,
2984 &server_session_timeout,
2985 s);
2986 GNUNET_log (TIMEOUT_LOG,
2987 "Timeout for session %p set to %s\n",
2988 s,
2989 GNUNET_STRINGS_relative_time_to_string (HTTP_SERVER_SESSION_TIMEOUT,
2990 GNUNET_YES));
2991}
2992
2993
2994/**
2995* Increment session timeout due to activity session s
2996*
2997* @param s the session
2998*/
2999static void
3000server_reschedule_session_timeout (struct Session *s)
3001{
3002 GNUNET_assert (NULL != s);
3003 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
3004
3005 GNUNET_SCHEDULER_cancel (s->timeout_task);
3006 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT,
3007 &server_session_timeout,
3008 s);
3009 GNUNET_log (TIMEOUT_LOG,
3010 "Timeout rescheduled for session %p set to %s\n",
3011 s,
3012 GNUNET_STRINGS_relative_time_to_string (HTTP_SERVER_SESSION_TIMEOUT,
3013 GNUNET_YES));
3014}
3015
3016
3017/**
3018 * Exit point from the plugin. 3001 * Exit point from the plugin.
3019 * 3002 *
3020 * @param cls api 3003 * @param cls api
@@ -3025,8 +3008,6 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
3025{ 3008{
3026 struct GNUNET_TRANSPORT_PluginFunctions *api = cls; 3009 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3027 struct HTTP_Server_Plugin *plugin = api->cls; 3010 struct HTTP_Server_Plugin *plugin = api->cls;
3028 struct Session *pos;
3029 struct Session *next;
3030 3011
3031 if (NULL == api->cls) 3012 if (NULL == api->cls)
3032 { 3013 {
@@ -3068,29 +3049,17 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
3068 /* Stop to report addresses to transport service */ 3049 /* Stop to report addresses to transport service */
3069 server_stop_report_addresses (plugin); 3050 server_stop_report_addresses (plugin);
3070 server_stop (plugin); 3051 server_stop (plugin);
3071 next = plugin->head; 3052 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
3072 while (NULL != (pos = next)) 3053 &destroy_session_cb,
3073 { 3054 plugin);
3074 next = pos->next; 3055 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
3075 LOG (GNUNET_ERROR_TYPE_DEBUG, 3056 plugin->sessions = NULL;
3076 "Removing left over session %p\n",
3077 pos);
3078
3079 if ((GNUNET_YES == pos->session_passed) && (GNUNET_NO == pos->session_ended))
3080 {
3081 /* Notify transport immediately that this session is invalid */
3082 pos->session_ended = GNUNET_YES;
3083 plugin->env->session_end (plugin->env->cls, pos->address, pos);
3084 }
3085 server_delete_session (plugin, pos);
3086 }
3087
3088 /* Clean up */ 3057 /* Clean up */
3089 GNUNET_free_non_null (plugin->external_hostname); 3058 GNUNET_free_non_null (plugin->external_hostname);
3090 GNUNET_free_non_null (plugin->ext_addr); 3059 GNUNET_free_non_null (plugin->ext_addr);
3091 GNUNET_free_non_null (plugin->server_addr_v4); 3060 GNUNET_free_non_null (plugin->server_addr_v4);
3092 GNUNET_free_non_null (plugin->server_addr_v6); 3061 GNUNET_free_non_null (plugin->server_addr_v6);
3093 regfree(&plugin->url_regex); 3062 regfree (&plugin->url_regex);
3094 3063
3095 LOG (GNUNET_ERROR_TYPE_DEBUG, 3064 LOG (GNUNET_ERROR_TYPE_DEBUG,
3096 _("Shutdown for plugin `%s' complete\n"), 3065 _("Shutdown for plugin `%s' complete\n"),
@@ -3136,12 +3105,67 @@ static enum GNUNET_ATS_Network_Type
3136http_server_get_network (void *cls, 3105http_server_get_network (void *cls,
3137 struct Session *session) 3106 struct Session *session)
3138{ 3107{
3139 GNUNET_assert (NULL != session);
3140 return ntohl (session->ats_address_network_type); 3108 return ntohl (session->ats_address_network_type);
3141} 3109}
3142 3110
3143 3111
3144/** 3112/**
3113 * Return information about the given session to the
3114 * monitor callback.
3115 *
3116 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3117 * @param peer peer we send information about
3118 * @param value our `struct Session` to send information about
3119 * @return #GNUNET_OK (continue to iterate)
3120 */
3121static int
3122send_session_info_iter (void *cls,
3123 const struct GNUNET_PeerIdentity *peer,
3124 void *value)
3125{
3126 struct HTTP_Server_Plugin *plugin = cls;
3127 struct Session *session = value;
3128
3129 notify_session_monitor (plugin,
3130 session,
3131 GNUNET_TRANSPORT_SS_UP);
3132 return GNUNET_OK;
3133}
3134
3135
3136/**
3137 * Begin monitoring sessions of a plugin. There can only
3138 * be one active monitor per plugin (i.e. if there are
3139 * multiple monitors, the transport service needs to
3140 * multiplex the generated events over all of them).
3141 *
3142 * @param cls closure of the plugin
3143 * @param sic callback to invoke, NULL to disable monitor;
3144 * plugin will being by iterating over all active
3145 * sessions immediately and then enter monitor mode
3146 * @param sic_cls closure for @a sic
3147 */
3148static void
3149http_server_plugin_setup_monitor (void *cls,
3150 GNUNET_TRANSPORT_SessionInfoCallback sic,
3151 void *sic_cls)
3152{
3153 struct HTTP_Server_Plugin *plugin = cls;
3154
3155 plugin->sic = sic;
3156 plugin->sic_cls = sic_cls;
3157 if (NULL != sic)
3158 {
3159 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
3160 &send_session_info_iter,
3161 plugin);
3162 /* signal end of first iteration */
3163 sic (sic_cls, NULL, NULL);
3164 }
3165}
3166
3167
3168/**
3145 * Entry point for the plugin. 3169 * Entry point for the plugin.
3146 * 3170 *
3147 * @param cls env 3171 * @param cls env
@@ -3167,6 +3191,8 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
3167 } 3191 }
3168 plugin = GNUNET_new (struct HTTP_Server_Plugin); 3192 plugin = GNUNET_new (struct HTTP_Server_Plugin);
3169 plugin->env = env; 3193 plugin->env = env;
3194 plugin->sessions = GNUNET_CONTAINER_multipeermap_create (128,
3195 GNUNET_YES);
3170 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions); 3196 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3171 api->cls = plugin; 3197 api->cls = plugin;
3172 api->send = &http_server_plugin_send; 3198 api->send = &http_server_plugin_send;
@@ -3181,6 +3207,8 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
3181 api->address_pretty_printer = &http_common_plugin_address_pretty_printer; 3207 api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
3182 api->get_network = &http_server_get_network; 3208 api->get_network = &http_server_get_network;
3183 api->update_session_timeout = &http_server_plugin_update_session_timeout; 3209 api->update_session_timeout = &http_server_plugin_update_session_timeout;
3210 // api->update_inbound_delay = &http_server_plugin_update_inbound_delay; // FIXME: implement/support!
3211 api->setup_monitor = &http_server_plugin_setup_monitor;
3184#if BUILD_HTTPS 3212#if BUILD_HTTPS
3185 plugin->name = "transport-https_server"; 3213 plugin->name = "transport-https_server";
3186 plugin->protocol = "https"; 3214 plugin->protocol = "https";
diff --git a/src/transport/test_transport_api_http_reverse_peer1.conf b/src/transport/test_transport_api_http_reverse_peer1.conf
index 351b29746..aebaf88e2 100644
--- a/src/transport/test_transport_api_http_reverse_peer1.conf
+++ b/src/transport/test_transport_api_http_reverse_peer1.conf
@@ -1,4 +1,4 @@
1INLINE@ template_cfg_peer1.conf 1@INLINE@ template_cfg_peer1.conf
2[PATHS] 2[PATHS]
3GNUNET_TEST_HOME = /tmp/test-transport/api-http-p1/ 3GNUNET_TEST_HOME = /tmp/test-transport/api-http-p1/
4 4
diff --git a/src/transport/test_transport_api_http_reverse_peer2.conf b/src/transport/test_transport_api_http_reverse_peer2.conf
index 0283d12b5..210e44a02 100644
--- a/src/transport/test_transport_api_http_reverse_peer2.conf
+++ b/src/transport/test_transport_api_http_reverse_peer2.conf
@@ -1,4 +1,4 @@
1INLINE@ template_cfg_peer2.conf 1@INLINE@ template_cfg_peer2.conf
2[PATHS] 2[PATHS]
3GNUNET_TEST_HOME = /tmp/test-transport/api-http-p2/ 3GNUNET_TEST_HOME = /tmp/test-transport/api-http-p2/
4 4
diff --git a/src/transport/transport-testing.c b/src/transport/transport-testing.c
index b2af478e1..d25d3f4b7 100644
--- a/src/transport/transport-testing.c
+++ b/src/transport/transport-testing.c
@@ -259,8 +259,8 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth
259 259
260 /* Create configuration and call testing lib to modify it */ 260 /* Create configuration and call testing lib to modify it */
261 p->cfg = GNUNET_CONFIGURATION_create (); 261 p->cfg = GNUNET_CONFIGURATION_create ();
262 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); 262 GNUNET_assert (GNUNET_OK ==
263 263 GNUNET_CONFIGURATION_load (p->cfg, cfgname));
264 if (GNUNET_SYSERR == GNUNET_TESTING_configuration_create (tth->tl_system, p->cfg)) 264 if (GNUNET_SYSERR == GNUNET_TESTING_configuration_create (tth->tl_system, p->cfg))
265 { 265 {
266 LOG (GNUNET_ERROR_TYPE_ERROR, 266 LOG (GNUNET_ERROR_TYPE_ERROR,
diff --git a/src/transport/transport.conf.in b/src/transport/transport.conf.in
index 20a878c2e..845c4d384 100644
--- a/src/transport/transport.conf.in
+++ b/src/transport/transport.conf.in
@@ -68,11 +68,11 @@ TESTING_IGNORE_KEYS = ACCEPT_FROM;
68# PROXY = 68# PROXY =
69 69
70# User name for proxy server 70# User name for proxy server
71# PROXY_USERNAME = 71# PROXY_USERNAME =
72# User password for proxy server 72# User password for proxy server
73# PROXY_PASSWORD = 73# PROXY_PASSWORD =
74 74
75# Type of proxy server, 75# Type of proxy server,
76# Valid values: HTTP, SOCKS4, SOCKS5, SOCKS4A, SOCKS5_HOSTNAME 76# Valid values: HTTP, SOCKS4, SOCKS5, SOCKS4A, SOCKS5_HOSTNAME
77# Default: HTTP 77# Default: HTTP
78# PROXY_TYPE = HTTP 78# PROXY_TYPE = HTTP
@@ -95,11 +95,11 @@ TESTING_IGNORE_KEYS = ACCEPT_FROM;
95# PROXY = 95# PROXY =
96 96
97# User name for proxy server 97# User name for proxy server
98# PROXY_USERNAME = 98# PROXY_USERNAME =
99# User password for proxy server 99# User password for proxy server
100# PROXY_PASSWORD = 100# PROXY_PASSWORD =
101 101
102# Type of proxy server, 102# Type of proxy server,
103# Valid values: HTTP, SOCKS4, SOCKS5, SOCKS4A, SOCKS5_HOSTNAME 103# Valid values: HTTP, SOCKS4, SOCKS5, SOCKS4A, SOCKS5_HOSTNAME
104# Default: HTTP 104# Default: HTTP
105# PROXY_TYPE = HTTP 105# PROXY_TYPE = HTTP