(no commit message)
[oweals/gnunet.git] / src / transport / plugin_transport_http_server.c
1 /*
2      This file is part of GNUnet
3      (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file transport/plugin_transport_http.c
23  * @brief http transport service plugin
24  * @author Matthias Wachs
25  */
26
27 #include "plugin_transport_http.h"
28
29 #define HTTP_ERROR_RESPONSE "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"><HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY><H1>Not Found</H1>The requested URL was not found on this server.<P><HR><ADDRESS></ADDRESS></BODY></HTML>"
30 #define _RECEIVE 0
31 #define _SEND 1
32
33 static void
34 server_log (void *arg, const char *fmt, va_list ap)
35 {
36   char text[1024];
37
38   vsnprintf (text, sizeof (text), fmt, ap);
39   va_end (ap);
40   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "server: %s\n", text);
41 }
42
43 struct ServerConnection
44 {
45   /* _RECV or _SEND */
46   int direction;
47
48   /* should this connection get disconnected? GNUNET_YES/NO  */
49   int disconnect;
50
51   struct Session *session;
52   struct MHD_Connection * mhd_conn;
53 };
54
55 /**
56  * Check if incoming connection is accepted.
57  * NOTE: Here every connection is accepted
58  * @param cls plugin as closure
59  * @param addr address of incoming connection
60  * @param addr_len address length of incoming connection
61  * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected
62  *
63  */
64 static int
65 server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len)
66 {
67   struct Plugin * plugin = cls;
68
69   if (plugin->cur_connections <= plugin->max_connections)
70     return MHD_YES;
71   else
72   {
73     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "server: Cannot accept new connections\n");
74     return MHD_NO;
75   }
76 }
77
78
79 /**
80  * Callback called by MHD when it needs data to send
81  * @param cls current session
82  * @param pos position in buffer
83  * @param buf the buffer to write data to
84  * @param max max number of bytes available in buffer
85  * @return bytes written to buffer
86  */
87 #if 0
88 static ssize_t
89 server_send_cb (void *cls, uint64_t pos, char *buf, size_t max)
90 {
91
92   return 0;
93 }
94 #endif
95
96
97 #if BUILD_HTTPS
98 static char *
99 server_load_file (const char *file)
100 {
101   struct GNUNET_DISK_FileHandle *gn_file;
102   struct stat fstat;
103   char *text = NULL;
104
105   if (0 != STAT (file, &fstat))
106     return NULL;
107   text = GNUNET_malloc (fstat.st_size + 1);
108   gn_file =
109       GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ,
110                              GNUNET_DISK_PERM_USER_READ);
111   if (gn_file == NULL)
112   {
113     GNUNET_free (text);
114     return NULL;
115   }
116   if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fstat.st_size))
117   {
118     GNUNET_free (text);
119     GNUNET_DISK_file_close (gn_file);
120     return NULL;
121   }
122   text[fstat.st_size] = '\0';
123   GNUNET_DISK_file_close (gn_file);
124   return text;
125 }
126 #endif
127
128
129 #if BUILD_HTTPS
130
131 static int
132 server_load_certificate (struct Plugin *plugin)
133 {
134   int res = GNUNET_OK;
135
136   char *key_file;
137   char *cert_file;
138
139   /* Get crypto init string from config
140    * If not present just use default values */
141   GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
142                                          "CRYPTO_INIT", &plugin->crypto_init);
143
144   if (GNUNET_OK !=
145       GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name,
146                                                "KEY_FILE", &key_file))
147   {
148     key_file = "https_key.key";
149   }
150
151   if (GNUNET_OK !=
152       GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name,
153                                                "CERT_FILE", &cert_file))
154   {
155     cert_file = "https_cert.crt";
156   }
157
158   /* read key & certificates from file */
159 #if VERBOSE_SERVER
160   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
161               "Loading TLS certificate from key-file `%s' cert-file`%s'\n",
162               key_file, cert_file);
163 #endif
164
165   plugin->key = server_load_file (key_file);
166   plugin->cert = server_load_file (cert_file);
167
168   if ((plugin->key == NULL) || (plugin->cert == NULL))
169   {
170     struct GNUNET_OS_Process *cert_creation;
171
172     GNUNET_free_non_null (plugin->key);
173     plugin->key = NULL;
174     GNUNET_free_non_null (plugin->cert);
175     plugin->cert = NULL;
176
177 #if VERBOSE_SERVER
178     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
179                 "No usable TLS certificate found, creating certificate\n");
180 #endif
181     errno = 0;
182     cert_creation =
183         GNUNET_OS_start_process (NULL, NULL,
184                                  "gnunet-transport-certificate-creation",
185                                  "gnunet-transport-certificate-creation",
186                                  key_file, cert_file, NULL);
187     if (cert_creation == NULL)
188     {
189       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
190                        _
191                        ("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n"));
192       GNUNET_free (key_file);
193       GNUNET_free (cert_file);
194
195       GNUNET_free_non_null (plugin->key);
196       GNUNET_free_non_null (plugin->cert);
197       GNUNET_free_non_null (plugin->crypto_init);
198
199       return GNUNET_SYSERR;
200     }
201     GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation));
202     GNUNET_OS_process_close (cert_creation);
203
204     plugin->key = server_load_file (key_file);
205     plugin->cert = server_load_file (cert_file);
206   }
207
208   if ((plugin->key == NULL) || (plugin->cert == NULL))
209   {
210     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
211                      _
212                      ("No usable TLS certificate found and creating one failed!\n"),
213                      "transport-https");
214     GNUNET_free (key_file);
215     GNUNET_free (cert_file);
216
217     GNUNET_free_non_null (plugin->key);
218     GNUNET_free_non_null (plugin->cert);
219     GNUNET_free_non_null (plugin->crypto_init);
220
221     return GNUNET_SYSERR;
222   }
223   GNUNET_free (key_file);
224   GNUNET_free (cert_file);
225 #if DEBUG_HTTP
226   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n");
227 #endif
228
229   return res;
230 }
231 #endif
232
233
234 /**
235  * Process GET or PUT request received via MHD.  For
236  * GET, queue response that will send back our pending
237  * messages.  For PUT, process incoming data and send
238  * to GNUnet core.  In either case, check if a session
239  * already exists and create a new one if not.
240  */
241 static int
242 server_access_cb (void *cls, struct MHD_Connection *mhd_connection,
243                   const char *url, const char *method, const char *version,
244                   const char *upload_data, size_t * upload_data_size,
245                   void **httpSessionCache)
246 {
247   struct Plugin *plugin = cls;
248   struct ServerConnection *sc = *httpSessionCache;
249   struct Session *s = NULL;
250
251   int res = MHD_YES;
252   struct MHD_Response *response;
253
254   GNUNET_assert (cls != NULL);
255   /* new connection */
256   if (sc == NULL)
257     {
258     uint32_t tag;
259     const union MHD_ConnectionInfo *conn_info;
260     size_t addrlen;
261     struct GNUNET_PeerIdentity target;
262     int check = GNUNET_NO;
263     struct Session * t;
264     int direction;
265
266     conn_info = MHD_get_connection_info (mhd_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS);
267     if (conn_info->client_addr->sa_family == AF_INET)
268       addrlen = sizeof (struct sockaddr_in);
269     else if (conn_info->client_addr->sa_family == AF_INET6)
270       addrlen = sizeof (struct sockaddr_in6);
271     else
272       return MHD_NO;
273
274     if ((strlen(&url[1]) >= 105)  && (url[104] == ';'))
275     {
276       char hash[104];
277       char * tagc = (char *) &url[105];
278       memcpy(&hash, &url[1], 103);
279       hash [103] = '\0';
280       if (GNUNET_OK == GNUNET_CRYPTO_hash_from_string ((const char *) &hash, &(target.hashPubKey)))
281       {
282         tag = strtoul (tagc, NULL, 10);
283         if (tagc > 0)
284           check = GNUNET_YES;
285       }
286     }
287
288     if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
289       direction = _RECEIVE;
290     if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
291       direction = _SEND;
292
293     if (check == GNUNET_NO)
294       goto error;
295 #if VERBOSE_SERVER
296     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "server: New inbound connection from %s with tag %u\n", GNUNET_h2s_full(&(target.hashPubKey)), tag);
297 #endif
298     /* find duplicate session */
299
300     t = plugin->head;
301
302     while (t != NULL)
303     {
304       if ((t->inbound) && (0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity))) &&
305           /* FIXME add source address comparison */
306           (t->tag == tag))
307       break;
308       t = t->next;
309     }
310     if (t != NULL)
311     {
312 #if VERBOSE_SERVER
313       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "server: Duplicate session, dismissing new connection from peer `%s'\n", GNUNET_i2s (&target));
314 #endif
315       goto error;
316     }
317
318     /* find semi-session */
319     t = plugin->server_semi_head;
320
321     while (t != NULL)
322     {
323       /* FIXME add source address comparison */
324       if ((0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity))) &&
325           (t->tag == tag))
326       {
327         break;
328       }
329       t = t->next;
330     }
331
332     if (t == NULL)
333       goto create;
334
335 #if VERBOSE_SERVER
336       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "server: Found existing semi-session for `%s'\n", GNUNET_i2s (&target));
337 #endif
338
339     if ((direction == _SEND) && (t->server_send != NULL))
340     {
341 #if VERBOSE_SERVER
342       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "server: Duplicate GET session, dismissing new connection from peer `%s'\n", GNUNET_i2s (&target));
343 #endif
344       goto error;
345     }
346     else
347     {
348       s = t;
349       GNUNET_CONTAINER_DLL_remove(plugin->server_semi_head, plugin->server_semi_tail, s);
350       GNUNET_CONTAINER_DLL_insert(plugin->head, plugin->tail, s);
351 #if VERBOSE_SERVER
352       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "server: Found matching semi-session, merging session for peer `%s'\n", GNUNET_i2s (&target));
353 #endif
354
355       goto found;
356     }
357     if ((direction == _RECEIVE) && (t->server_recv != NULL))
358     {
359 #if VERBOSE_SERVER
360       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "server: Duplicate PUT session, dismissing new connection from peer `%s'\n", GNUNET_i2s (&target));
361 #endif
362       goto error;
363     }
364     else
365     {
366       s = t;
367       GNUNET_CONTAINER_DLL_remove(plugin->server_semi_head, plugin->server_semi_tail, s);
368       GNUNET_CONTAINER_DLL_insert(plugin->head, plugin->tail, s);
369 #if VERBOSE_SERVER
370       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "server: Found matching semi-session, merging session for peer `%s'\n", GNUNET_i2s (&target));
371 #endif
372       goto found;
373     }
374
375 create:
376 /* create new session */
377 #if VERBOSE_SERVER
378       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "server: Creating new session for peer `%s' \n", GNUNET_i2s (&target));
379 #endif
380
381     s = create_session(plugin,
382                         &target,
383                         conn_info->client_addr,
384                         addrlen,
385                         NULL,
386                         NULL);
387
388     s->inbound = GNUNET_YES;
389     s->tag= tag;
390     if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
391       s->server_recv = s;
392     if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
393       s->server_send = s;
394     GNUNET_CONTAINER_DLL_insert (plugin->server_semi_head, plugin->server_semi_tail, s);
395
396     goto found;
397 error:
398         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "server: Invalid connection request\n");
399         response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
400         res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
401         MHD_destroy_response (response);
402         return res;
403
404
405 found:
406
407
408     sc = GNUNET_malloc (sizeof (struct ServerConnection));
409     sc->mhd_conn = mhd_connection;
410     sc->direction = direction;
411     sc->session = s;
412     if (direction == _SEND)
413       s->server_send = sc;
414     if (direction == _RECEIVE)
415       s->server_recv = sc;
416
417     (*httpSessionCache) = sc;
418     return MHD_YES;
419   }
420   /* existing connection */
421   sc = (*httpSessionCache);
422   s = sc->session;
423
424   /* connection is to be disconnected*/
425   if (sc->disconnect == GNUNET_YES)
426   {
427     response = MHD_create_response_from_data (strlen ("Thank you!"), "Thank you!", MHD_NO, MHD_NO);
428     res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
429 #if VERBOSE_SERVER
430     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
431                 "Sent HTTP/1.1: 200 OK as PUT Response\n");
432 #endif
433     MHD_destroy_response (response);
434     return MHD_YES;
435   }
436
437   return res;
438 }
439
440 static void
441 server_disconnect_cb (void *cls, struct MHD_Connection *connection,
442                       void **httpSessionCache)
443 {
444   struct ServerConnection *sc = *httpSessionCache;
445   struct ServerConnection *tc = *httpSessionCache;
446   struct Session * s = NULL;
447   struct Session * t = NULL;
448   struct Plugin * plugin = NULL;
449
450   if (sc == NULL)
451     return;
452
453   s = sc->session;
454   plugin = s-> plugin;
455   if (sc->direction == _SEND)
456   {
457 #if VERBOSE_SERVER
458   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
459                    "Server: peer `%s' PUT on address `%s' disconnected\n",
460                    GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen));
461 #endif
462     s->server_send = NULL;
463     /* FIXME miminimize timeout here */
464     if (s->server_recv != NULL)
465     {
466       tc = s->server_recv;
467       tc->disconnect = GNUNET_YES;
468     }
469   }
470   if (sc->direction == _RECEIVE)
471   {
472 #if VERBOSE_SERVER
473   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
474                    "Server: peer `%s' GET on address `%s' disconnected\n",
475                    GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen));
476 #endif
477     s->server_recv = NULL;
478     //MHD_
479     if (s->server_send != NULL)
480     {
481       tc = s->server_send;
482       tc->disconnect = GNUNET_YES;
483     }
484   }
485   GNUNET_free (sc);
486
487   t = plugin->server_semi_head;
488   while (t != NULL)
489   {
490     if (t == s)
491     {
492       GNUNET_CONTAINER_DLL_remove(plugin->server_semi_head, plugin->server_semi_tail, s);
493       GNUNET_CONTAINER_DLL_insert(plugin->head, plugin->tail, s);
494       break;
495     }
496     t = t->next;
497   }
498
499   if ((s->server_send == NULL) && (s->server_recv == NULL))
500   {
501 #if VERBOSE_SERVER
502   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
503                    "Server: peer `%s' on address `%s' disconnected\n",
504                    GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen));
505 #endif
506     notify_session_end(s->plugin, &s->target, s);
507   }
508 }
509
510 int
511 server_disconnect (struct Session *s)
512 {
513   struct Plugin *plugin = s->plugin;
514   struct Session *t = plugin->head;
515
516   while (t != NULL)
517   {
518     if (t->inbound == GNUNET_YES)
519     {
520       if (t->server_send != NULL)
521       {
522         ((struct ServerConnection *) t->server_send)->disconnect = GNUNET_YES;
523       }
524       if (t->server_send != NULL)
525       {
526         ((struct ServerConnection *) t->server_send)->disconnect = GNUNET_YES;
527       }
528     }
529     t = t->next;
530   }
531
532
533   return GNUNET_OK;
534 }
535
536 int
537 server_send (struct Session *s, const char *msgbuf, size_t msgbuf_size)
538 {
539   return GNUNET_OK;
540 }
541
542 /**
543  * Function that queries MHD's select sets and
544  * starts the task waiting for them.
545  * @param plugin plugin
546  * @param daemon_handle the MHD daemon handle
547  * @return gnunet task identifier
548  */
549 static GNUNET_SCHEDULER_TaskIdentifier
550 server_schedule (struct Plugin *plugin, struct MHD_Daemon *daemon_handle);
551
552 /**
553  * Call MHD IPv4 to process pending requests and then go back
554  * and schedule the next run.
555  * @param cls plugin as closure
556  * @param tc task context
557  */
558 static void
559 server_v4_run (void *cls,
560                            const struct GNUNET_SCHEDULER_TaskContext *tc)
561 {
562   struct Plugin *plugin = cls;
563   GNUNET_assert (cls != NULL);
564
565   plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
566
567   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
568     return;
569
570   GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4));
571   plugin->server_v4_task = server_schedule (plugin, plugin->server_v4);
572 }
573
574
575 /**
576  * Call MHD IPv6 to process pending requests and then go back
577  * and schedule the next run.
578  * @param cls plugin as closure
579  * @param tc task context
580  */
581 static void
582 server_v6_run (void *cls,
583                            const struct GNUNET_SCHEDULER_TaskContext *tc)
584 {
585   struct Plugin *plugin = cls;
586   GNUNET_assert (cls != NULL);
587
588   plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
589
590   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
591     return;
592
593   GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6));
594   plugin->server_v6_task = server_schedule (plugin, plugin->server_v6);
595 }
596
597 /**
598  * Function that queries MHD's select sets and
599  * starts the task waiting for them.
600  * @param plugin plugin
601  * @param daemon_handle the MHD daemon handle
602  * @return gnunet task identifier
603  */
604 static GNUNET_SCHEDULER_TaskIdentifier
605 server_schedule (struct Plugin *plugin, struct MHD_Daemon *daemon_handle)
606 {
607   GNUNET_SCHEDULER_TaskIdentifier ret;
608   fd_set rs;
609   fd_set ws;
610   fd_set es;
611   struct GNUNET_NETWORK_FDSet *wrs;
612   struct GNUNET_NETWORK_FDSet *wws;
613   struct GNUNET_NETWORK_FDSet *wes;
614   int max;
615   unsigned long long timeout;
616   int haveto;
617   struct GNUNET_TIME_Relative tv;
618
619   ret = GNUNET_SCHEDULER_NO_TASK;
620   FD_ZERO (&rs);
621   FD_ZERO (&ws);
622   FD_ZERO (&es);
623   wrs = GNUNET_NETWORK_fdset_create ();
624   wes = GNUNET_NETWORK_fdset_create ();
625   wws = GNUNET_NETWORK_fdset_create ();
626   max = -1;
627   GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max));
628   haveto = MHD_get_timeout (daemon_handle, &timeout);
629   if (haveto == MHD_YES)
630     tv.rel_value = (uint64_t) timeout;
631   else
632     tv = GNUNET_TIME_UNIT_SECONDS;
633   GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
634   GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
635   GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
636   if (daemon_handle == plugin->server_v4)
637   {
638     if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK)
639     {
640       GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
641       plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
642     }
643
644     ret =
645         GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
646                                      GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws,
647                                      &server_v4_run, plugin);
648   }
649   if (daemon_handle == plugin->server_v6)
650   {
651     if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK)
652     {
653       GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
654       plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
655     }
656
657     ret =
658         GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
659                                      GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws,
660                                      &server_v6_run, plugin);
661   }
662   GNUNET_NETWORK_fdset_destroy (wrs);
663   GNUNET_NETWORK_fdset_destroy (wws);
664   GNUNET_NETWORK_fdset_destroy (wes);
665   return ret;
666 }
667
668 int
669 server_start (struct Plugin *plugin)
670 {
671   int res = GNUNET_OK;
672
673 #if BUILD_HTTPS
674   res = server_load_certificate (plugin);
675   if (res == GNUNET_SYSERR)
676   {
677     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TABORT\n");
678     return res;
679   }
680 #endif
681
682   plugin->server_v4 = NULL;
683   if (plugin->ipv4 == GNUNET_YES)
684   {
685     plugin->server_v4 = MHD_start_daemon (
686 #if VERBOSE_SERVER
687                                            MHD_USE_DEBUG |
688 #endif
689 #if BUILD_HTTPS
690                                            MHD_USE_SSL |
691 #endif
692                                            MHD_NO_FLAG, plugin->port,
693                                            &server_accept_cb, plugin,
694                                            &server_access_cb, plugin,
695                                            //MHD_OPTION_SOCK_ADDR,
696                                            //(struct sockaddr_in *)
697                                            //plugin->bind4_address,
698                                            MHD_OPTION_CONNECTION_LIMIT,
699                                            (unsigned int)
700                                            plugin->max_connections,
701 #if BUILD_HTTPS
702                                            MHD_OPTION_HTTPS_PRIORITIES,
703                                            plugin->crypto_init,
704                                            MHD_OPTION_HTTPS_MEM_KEY,
705                                            plugin->key,
706                                            MHD_OPTION_HTTPS_MEM_CERT,
707                                            plugin->cert,
708 #endif
709                                            MHD_OPTION_CONNECTION_TIMEOUT,
710                                            (unsigned int) 3,
711                                            MHD_OPTION_CONNECTION_MEMORY_LIMIT,
712                                            (size_t) (2 *
713                                                      GNUNET_SERVER_MAX_MESSAGE_SIZE),
714                                            MHD_OPTION_NOTIFY_COMPLETED,
715                                            &server_disconnect_cb, plugin,
716                                            MHD_OPTION_EXTERNAL_LOGGER,
717                                            server_log, NULL, MHD_OPTION_END);
718     if (plugin->server_v4 == NULL)
719       res = GNUNET_SYSERR;
720   }
721   plugin->server_v6 = NULL;
722   if (plugin->ipv6 == GNUNET_YES)
723   {
724     plugin->server_v6 = MHD_start_daemon (
725 #if VERBOSE_SERVER
726                                            MHD_USE_DEBUG |
727 #endif
728 #if BUILD_HTTPS
729                                            MHD_USE_SSL |
730 #endif
731                                            MHD_USE_IPv6, plugin->port,
732                                            &server_accept_cb, plugin,
733                                            &server_access_cb, plugin,
734                                            //MHD_OPTION_SOCK_ADDR,
735                                            //tmp,
736                                            MHD_OPTION_CONNECTION_LIMIT,
737                                            (unsigned int)
738                                            plugin->max_connections,
739 #if BUILD_HTTPS
740                                            MHD_OPTION_HTTPS_PRIORITIES,
741                                            plugin->crypto_init,
742                                            MHD_OPTION_HTTPS_MEM_KEY,
743                                            plugin->key,
744                                            MHD_OPTION_HTTPS_MEM_CERT,
745                                            plugin->cert,
746 #endif
747                                            MHD_OPTION_CONNECTION_TIMEOUT,
748                                            (unsigned int) 3,
749                                            MHD_OPTION_CONNECTION_MEMORY_LIMIT,
750                                            (size_t) (2 *
751                                                      GNUNET_SERVER_MAX_MESSAGE_SIZE),
752                                            MHD_OPTION_NOTIFY_COMPLETED,
753                                            &server_disconnect_cb, plugin,
754                                            MHD_OPTION_EXTERNAL_LOGGER,
755                                            server_log, NULL, MHD_OPTION_END);
756
757     if (plugin->server_v6 == NULL)
758       res = GNUNET_SYSERR;
759   }
760
761   if (plugin->server_v4 != NULL)
762     plugin->server_v4_task = server_schedule (plugin, plugin->server_v4);
763   if (plugin->server_v6 != NULL)
764     plugin->server_v6_task = server_schedule (plugin, plugin->server_v6);
765
766 #if DEBUG_HTTP
767   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
768                    "%s server component started on port %u\n", plugin->name,
769                    plugin->port);
770 #endif
771   return res;
772 }
773
774 void
775 server_stop (struct Plugin *plugin)
776 {
777   struct Session *s = NULL;
778   struct Session *t = NULL;
779
780   if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK)
781   {
782     GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
783     plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
784   }
785
786   if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK)
787   {
788     GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
789     plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
790   }
791
792   if (plugin->server_v4 != NULL)
793   {
794     MHD_stop_daemon (plugin->server_v4);
795     plugin->server_v4 = NULL;
796   }
797   if (plugin->server_v6 != NULL)
798   {
799     MHD_stop_daemon (plugin->server_v6);
800     plugin->server_v6 = NULL;
801   }
802
803   /* cleaning up semi-sessions never propagated */
804   s = plugin->server_semi_head;
805   while (s != NULL)
806   {
807     t = s->next;
808     delete_session (s);
809     s = t;
810   }
811
812 #if BUILD_HTTPS
813   GNUNET_free_non_null (plugin->crypto_init);
814   GNUNET_free_non_null (plugin->cert);
815   GNUNET_free_non_null (plugin->key);
816 #endif
817
818 #if DEBUG_HTTP
819   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
820                    "%s server component stopped\n", plugin->name);
821 #endif
822 }
823
824
825
826 /* end of plugin_transport_http.c */