mysql hacking
[oweals/gnunet.git] / src / transport / plugin_transport_https.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_https.c
23  * @brief https transport service plugin
24  * @author Matthias Wachs
25  */
26
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_constants.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_connection_lib.h"
32 #include "gnunet_service_lib.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_resolver_service.h"
36 #include "gnunet_server_lib.h"
37 #include "gnunet_container_lib.h"
38 #include "plugin_transport.h"
39 #include "gnunet_os_lib.h"
40 #include "gnunet_disk_lib.h"
41 #include "microhttpd.h"
42 #include <curl/curl.h>
43
44 #define DEBUG_HTTPS GNUNET_NO
45 #define VERBOSE GNUNET_NO
46 #define DEBUG_CURL GNUNET_NO
47 #define DEBUG_CONNECTIONS GNUNET_NO
48 #define DEBUG_SESSION_SELECTION GNUNET_NO
49
50 #define INBOUND GNUNET_NO
51 #define OUTBOUND GNUNET_YES
52
53 #define PROTOCOL_PREFIX "https"
54
55 /**
56  * Text of the response sent back after the last bytes of a PUT
57  * request have been received (just to formally obey the HTTP
58  * protocol).
59  */
60 #define HTTP_PUT_RESPONSE "Thank you!"
61
62 /**
63  * After how long do we expire an address that we
64  * learned from another peer if it is not reconfirmed
65  * by anyone?
66  */
67 #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
68
69 /**
70  * Page returned if request invalid
71  */
72 #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>"
73
74 /**
75  * Timeout for a http connect
76  */
77 #define HTTP_CONNECT_TIMEOUT 30
78
79 /**
80  * Network format for IPv4 addresses.
81  */
82 struct IPv4HttpAddress
83 {
84   /**
85    * IPv4 address, in network byte order.
86    */
87   uint32_t ipv4_addr GNUNET_PACKED;
88
89   /**
90    * Port number, in network byte order.
91    */
92   uint16_t u_port GNUNET_PACKED;
93
94 };
95
96
97 /**
98  * Network format for IPv6 addresses.
99  */
100 struct IPv6HttpAddress
101 {
102   /**
103    * IPv6 address.
104    */
105   struct in6_addr ipv6_addr GNUNET_PACKED;
106
107   /**
108    * Port number, in network byte order.
109    */
110   uint16_t u6_port GNUNET_PACKED;
111
112 };
113
114
115 /**
116  *  Message to send using http
117  */
118 struct HTTP_Message
119 {
120   /**
121    * next pointer for double linked list
122    */
123   struct HTTP_Message * next;
124
125   /**
126    * previous pointer for double linked list
127    */
128   struct HTTP_Message * prev;
129
130   /**
131    * buffer containing data to send
132    */
133   char *buf;
134
135   /**
136    * amount of data already sent
137    */
138   size_t pos;
139
140   /**
141    * buffer length
142    */
143   size_t size;
144
145   /**
146    * Continuation function to call once the transmission buffer
147    * has again space available.  NULL if there is no
148    * continuation to call.
149    */
150   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
151
152   /**
153    * Closure for transmit_cont.
154    */
155   void *transmit_cont_cls;
156 };
157
158
159 struct HTTP_PeerContext
160 {
161   /**
162    * peer's identity
163    */
164   struct GNUNET_PeerIdentity identity;
165
166   /**
167    * Pointer to the global plugin struct.
168    */
169   struct Plugin *plugin;
170
171   /**
172    * Linked list of connections with this peer
173    * head
174    */
175   struct Session * head;
176
177   /**
178    * Linked list of connections with this peer
179    * tail
180    */
181   struct Session * tail;
182
183   /**
184    * id for next session
185    */
186   size_t session_id_counter;
187
188   /**
189    * Last session used to send data
190    */
191   struct Session * last_session;
192 };
193
194
195 struct Session
196 {
197   /**
198    * API requirement.
199    */
200   struct SessionHeader header;
201
202   /**
203    * next session in linked list
204    */
205   struct Session * next;
206
207   /**
208    * previous session in linked list
209    */
210   struct Session * prev;
211
212   /**
213    * address of this session
214    */
215   void * addr;
216
217   /**
218    * address length
219    */
220   size_t addrlen;
221
222   /**
223    * target url
224    */
225   char * url;
226
227   /**
228    * Message queue for outbound messages
229    * head of queue
230    */
231   struct HTTP_Message * pending_msgs_head;
232
233   /**
234    * Message queue for outbound messages
235    * tail of queue
236    */
237   struct HTTP_Message * pending_msgs_tail;
238
239   /**
240    * partner peer this connection belongs to
241    */
242   struct HTTP_PeerContext * peercontext;
243
244   /**
245    * message stream tokenizer for incoming data
246    */
247   struct GNUNET_SERVER_MessageStreamTokenizer *msgtok;
248
249   /**
250    * session direction
251    * outbound: OUTBOUND (GNUNET_YES)
252    * inbound : INBOUND (GNUNET_NO)
253    */
254   unsigned int direction;
255
256   /**
257    * is session connected to send data?
258    */
259   unsigned int send_connected;
260
261   /**
262    * is send connection active?
263    */
264   unsigned int send_active;
265
266   /**
267    * connection disconnect forced (e.g. from transport)
268    */
269   unsigned int send_force_disconnect;
270
271   /**
272    * is session connected to receive data?
273    */
274   unsigned int recv_connected;
275
276   /**
277    * is receive connection active?
278    */
279   unsigned int recv_active;
280
281   /**
282    * connection disconnect forced (e.g. from transport)
283    */
284   unsigned int recv_force_disconnect;
285
286   /**
287    * id for next session
288    * NOTE: 0 is not an ID, zero is not defined. A correct ID is always > 0
289    */
290   size_t session_id;
291
292   /**
293    * entity managing sending data
294    * outbound session: CURL *
295    * inbound session: mhd_connection *
296    */
297   void * send_endpoint;
298
299   /**
300    * entity managing recieving data
301    * outbound session: CURL *
302    * inbound session: mhd_connection *
303    */
304   void * recv_endpoint;
305 };
306
307 /**
308  * Encapsulation of all of the state of the plugin.
309  */
310 struct Plugin
311 {
312   /**
313    * Our environment.
314    */
315   struct GNUNET_TRANSPORT_PluginEnvironment *env;
316
317   /**
318    * Handle for reporting statistics.
319    */
320   struct GNUNET_STATISTICS_Handle *stats;
321
322   unsigned int port_inbound;
323
324   struct GNUNET_CONTAINER_MultiHashMap *peers;
325
326   /**
327    * Daemon for listening for new IPv4 connections.
328    */
329   struct MHD_Daemon *http_server_daemon_v4;
330
331   /**
332    * Daemon for listening for new IPv6connections.
333    */
334   struct MHD_Daemon *http_server_daemon_v6;
335
336   /**
337    * Our primary task for http daemon handling IPv4 connections
338    */
339   GNUNET_SCHEDULER_TaskIdentifier http_server_task_v4;
340
341   /**
342    * Our primary task for http daemon handling IPv6 connections
343    */
344   GNUNET_SCHEDULER_TaskIdentifier http_server_task_v6;
345
346   /**
347    * The task sending data
348    */
349   GNUNET_SCHEDULER_TaskIdentifier http_curl_task;
350
351   /**
352    * cURL Multihandle
353    */
354   CURLM * multi_handle;
355
356   /**
357    * Our ASCII encoded, hashed peer identity
358    * This string is used to distinguish between connections and is added to the urls
359    */
360   struct GNUNET_CRYPTO_HashAsciiEncoded my_ascii_hash_ident;
361
362   struct sockaddr_in * bind4_address;
363   struct sockaddr_in6 * bind6_address;
364   char * bind_hostname;
365   int use_ipv6;
366   int use_ipv4;
367
368   /* The certificate MHD uses as an \0 terminated string */
369   char * cert;
370
371   /* The private key MHD uses as an \0 terminated string */
372   char * key;
373 };
374
375
376 /**
377  * Function called for a quick conversion of the binary address to
378  * a numeric address.  Note that the caller must not free the
379  * address and that the next call to this function is allowed
380  * to override the address again.
381  *
382  * @param cls closure
383  * @param addr binary address
384  * @param addrlen length of the address
385  * @return string representing the same address
386  */
387 static const char*
388 http_plugin_address_to_string (void *cls,
389                                    const void *addr,
390                                    size_t addrlen);
391
392
393 /**
394  * Call MHD to process pending ipv4 requests and then go back
395  * and schedule the next run.
396  */
397 static void http_server_daemon_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
398 /**
399  * Call MHD to process pending ipv6 requests and then go back
400  * and schedule the next run.
401  */
402 static void http_server_daemon_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
403
404 /**
405  * Function setting up curl handle and selecting message to send
406  * @param cls plugin
407  * @param ses session to send data to
408  * @param con connection
409  * @return bytes sent to peer
410  */
411 static ssize_t send_check_connections (void *cls, struct Session *ps);
412
413 /**
414  * Function setting up file descriptors and scheduling task to run
415  * @param cls closure
416  * @param ses session to send data to
417  * @param
418  */
419 static int curl_schedule(void *cls );
420
421
422
423 static char * create_url(void * cls, const void * addr, size_t addrlen, size_t id)
424 {
425   struct Plugin *plugin = cls;
426   char *url = NULL;
427
428   GNUNET_assert ((addr!=NULL) && (addrlen != 0));
429   GNUNET_asprintf(&url,
430                   "%s://%s/%s;%u", PROTOCOL_PREFIX,
431                   http_plugin_address_to_string(NULL, addr, addrlen),
432                   (char *) (&plugin->my_ascii_hash_ident),id);
433
434   return url;
435 }
436
437 /**
438  * Removes a message from the linked list of messages
439  * @param con connection to remove message from
440  * @param msg message to remove
441  * @return GNUNET_SYSERR if msg not found, GNUNET_OK on success
442  */
443 static int remove_http_message (struct Session * ps, struct HTTP_Message * msg)
444 {
445   GNUNET_CONTAINER_DLL_remove(ps->pending_msgs_head,ps->pending_msgs_tail,msg);
446   GNUNET_free(msg);
447   return GNUNET_OK;
448 }
449
450 int remove_peer_context_Iterator (void *cls, const GNUNET_HashCode *key, void *value);
451
452 /**
453  * Removes a session from the linked list of sessions
454  * @param pc peer context
455  * @param ps session
456  * @param call_msg_cont GNUNET_YES to call pending message continuations, otherwise no
457  * @param call_msg_cont_result, result to call message continuations with
458  * @return GNUNET_SYSERR if msg not found, GNUNET_OK on success
459  */
460 static int remove_session (struct HTTP_PeerContext * pc, struct Session * ps,  int call_msg_cont, int call_msg_cont_result)
461 {
462   struct HTTP_Message * msg;
463   struct Plugin * plugin = ps->peercontext->plugin;
464
465 #if DEBUG_CONNECTIONS
466   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: removing %s session %X with id %u\n", ps, (ps->direction == INBOUND) ? "inbound" : "outbound", ps, ps->session_id);
467 #endif
468   plugin->env->session_end(plugin, &pc->identity, ps);
469
470   GNUNET_free_non_null (ps->addr);
471   GNUNET_SERVER_mst_destroy (ps->msgtok);
472   GNUNET_free(ps->url);
473
474   if (ps->direction==INBOUND)
475   {
476           if (ps->recv_endpoint != NULL)
477           {
478                   curl_easy_cleanup(ps->recv_endpoint);
479                   ps->recv_endpoint = NULL;
480           }
481           if (ps->send_endpoint != NULL)
482           {
483                   curl_easy_cleanup(ps->send_endpoint);
484                   ps->send_endpoint = NULL;
485           }
486   }
487
488   msg = ps->pending_msgs_head;
489   while (msg!=NULL)
490   {
491     if ((call_msg_cont == GNUNET_YES) && (msg->transmit_cont!=NULL))
492     {
493       msg->transmit_cont (msg->transmit_cont_cls,&pc->identity,call_msg_cont_result);
494     }
495     GNUNET_free(msg);
496     GNUNET_CONTAINER_DLL_remove(ps->pending_msgs_head,ps->pending_msgs_head,msg);
497     msg = ps->pending_msgs_head;
498   }
499
500   GNUNET_CONTAINER_DLL_remove(pc->head,pc->tail,ps);
501   GNUNET_free(ps);
502   ps = NULL;
503
504   /* no sessions left remove peer */
505   if (pc->head==NULL)
506   {
507 #if DEBUG_HTTPS
508   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No sessions left for peer `%s', removing context\n",GNUNET_i2s(&pc->identity));
509 #endif
510         remove_peer_context_Iterator(plugin, &pc->identity.hashPubKey, pc);
511   }
512
513   return GNUNET_OK;
514 }
515
516 int remove_peer_context_Iterator (void *cls, const GNUNET_HashCode *key, void *value)
517 {
518   struct Plugin *plugin = cls;
519   struct HTTP_PeerContext * pc = value;
520   struct Session * ps = pc->head;
521   struct Session * tmp = NULL;
522   struct HTTP_Message * msg = NULL;
523   struct HTTP_Message * msg_tmp = NULL;
524 #if DEBUG_HTTPS
525   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Freeing context for peer `%s'\n",GNUNET_i2s(&pc->identity));
526 #endif
527   GNUNET_CONTAINER_multihashmap_remove (plugin->peers, &pc->identity.hashPubKey, pc);
528   while (ps!=NULL)
529   {
530         plugin->env->session_end(plugin, &pc->identity, ps);
531         tmp = ps->next;
532
533     GNUNET_free_non_null (ps->addr);
534     GNUNET_free(ps->url);
535     if (ps->msgtok != NULL)
536       GNUNET_SERVER_mst_destroy (ps->msgtok);
537
538     msg = ps->pending_msgs_head;
539     while (msg!=NULL)
540     {
541       msg_tmp = msg->next;
542       GNUNET_free(msg);
543       msg = msg_tmp;
544     }
545     if (ps->direction==OUTBOUND)
546     {
547       if (ps->send_endpoint!=NULL)
548         curl_easy_cleanup(ps->send_endpoint);
549       if (ps->recv_endpoint!=NULL)
550         curl_easy_cleanup(ps->recv_endpoint);
551     }
552
553     GNUNET_free(ps);
554     ps=tmp;
555   }
556   GNUNET_free(pc);
557   GNUNET_STATISTICS_update (plugin->env->stats,
558                             gettext_noop ("# HTTP peers active"),
559                             -1,
560                             GNUNET_NO);
561   return GNUNET_YES;
562 }
563
564 /**
565  * Add the IP of our network interface to the list of
566  * our external IP addresses.
567  *
568  * @param cls the 'struct Plugin*'
569  * @param name name of the interface
570  * @param isDefault do we think this may be our default interface
571  * @param addr address of the interface
572  * @param addrlen number of bytes in addr
573  * @return GNUNET_OK to continue iterating
574  */
575 static int
576 process_interfaces (void *cls,
577                     const char *name,
578                     int isDefault,
579                     const struct sockaddr *addr, socklen_t addrlen)
580 {
581   struct Plugin *plugin = cls;
582   struct IPv4HttpAddress * t4;
583   struct IPv6HttpAddress * t6;
584   int af;
585
586
587   GNUNET_assert(cls !=NULL);
588   af = addr->sa_family;
589   if ((af == AF_INET) && (plugin->use_ipv4 == GNUNET_YES) && (plugin->bind6_address == NULL))
590     {
591           struct in_addr bnd_cmp = ((struct sockaddr_in *) addr)->sin_addr;
592       t4 = GNUNET_malloc(sizeof(struct IPv4HttpAddress));
593       /* Not skipping loopback addresses
594       if (INADDR_LOOPBACK == ntohl(((struct sockaddr_in *) addr)->sin_addr.s_addr))
595       {
596
597         return GNUNET_OK;
598       }
599       */
600       t4->ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
601       t4->u_port = htons (plugin->port_inbound);
602       if (plugin->bind4_address != NULL)
603       {
604           if (0 == memcmp(&plugin->bind4_address->sin_addr, &bnd_cmp, sizeof (struct in_addr)))
605           {
606                   plugin->env->notify_address(plugin->env->cls,"https",t4, sizeof (struct IPv4HttpAddress), GNUNET_TIME_UNIT_FOREVER_REL);
607           }
608       }
609       else
610       {
611           plugin->env->notify_address(plugin->env->cls,"https",t4, sizeof (struct IPv4HttpAddress), GNUNET_TIME_UNIT_FOREVER_REL);
612       }
613       GNUNET_free (t4);
614     }
615   else if ((af == AF_INET6) && (plugin->use_ipv6 == GNUNET_YES)  && (plugin->bind4_address == NULL))
616     {
617           struct in6_addr bnd_cmp6 = ((struct sockaddr_in6 *) addr)->sin6_addr;
618       t6 = GNUNET_malloc(sizeof(struct IPv6HttpAddress));
619       if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
620         {
621           return GNUNET_OK;
622         }
623
624       if (plugin->bind6_address != NULL)
625       {
626           if (0 == memcmp(&plugin->bind6_address->sin6_addr, &bnd_cmp6, sizeof (struct in6_addr)))
627           {
628               memcpy (&t6->ipv6_addr,
629                       &((struct sockaddr_in6 *) addr)->sin6_addr,
630                       sizeof (struct in6_addr));
631               t6->u6_port = htons (plugin->port_inbound);
632               plugin->env->notify_address(plugin->env->cls,"https",t6,sizeof (struct IPv6HttpAddress) , GNUNET_TIME_UNIT_FOREVER_REL);
633           }
634       }
635       else
636       {
637           memcpy (&t6->ipv6_addr,
638                   &((struct sockaddr_in6 *) addr)->sin6_addr,
639                   sizeof (struct in6_addr));
640           t6->u6_port = htons (plugin->port_inbound);
641           plugin->env->notify_address(plugin->env->cls,"https",t6,sizeof (struct IPv6HttpAddress) , GNUNET_TIME_UNIT_FOREVER_REL);
642       }
643       GNUNET_free (t6);
644     }
645   return GNUNET_OK;
646 }
647
648
649 /**
650  * Callback called by MHD when a connection is terminated
651  */
652 static void mhd_termination_cb (void *cls, struct MHD_Connection * connection, void **httpSessionCache)
653 {
654   struct Session * ps = *httpSessionCache;
655   if (ps == NULL)
656     return;
657   struct HTTP_PeerContext * pc = ps->peercontext;
658
659   if (connection==ps->recv_endpoint)
660   {
661 #if DEBUG_CONNECTIONS
662     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound connection from peer `%s' was terminated\n", ps, GNUNET_i2s(&pc->identity));
663 #endif
664     ps->recv_active = GNUNET_NO;
665     ps->recv_connected = GNUNET_NO;
666     ps->recv_endpoint = NULL;
667   }
668   if (connection==ps->send_endpoint)
669   {
670
671     ps->send_active = GNUNET_NO;
672     ps->send_connected = GNUNET_NO;
673     ps->send_endpoint = NULL;
674 #if DEBUG_CONNECTIONS
675     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound connection from peer `%s' was terminated\n", ps, GNUNET_i2s(&pc->identity));
676 #endif
677   }
678
679   /* if both connections disconnected, remove session */
680   if ((ps->send_connected == GNUNET_NO) && (ps->recv_connected == GNUNET_NO))
681   {
682       GNUNET_STATISTICS_update (pc->plugin->env->stats,
683                             gettext_noop ("# HTTPS inbound sessions for peers active"),
684                             -1,
685                             GNUNET_NO);
686     remove_session(pc,ps,GNUNET_YES,GNUNET_SYSERR);
687   }
688 }
689
690 static void mhd_write_mst_cb (void *cls,
691                               void *client,
692                               const struct GNUNET_MessageHeader *message)
693 {
694
695   struct Session *ps  = cls;
696   struct HTTP_PeerContext *pc = ps->peercontext;
697   GNUNET_assert(ps != NULL);
698   GNUNET_assert(pc != NULL);
699 #if DEBUG_HTTPS
700   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
701               "Connection %X: Forwarding message to transport service, type %u and size %u from `%s' (`%s')\n",
702               ps,
703               ntohs(message->type),
704               ntohs(message->size),
705               GNUNET_i2s(&(ps->peercontext)->identity),http_plugin_address_to_string(NULL,ps->addr,ps->addrlen));
706 #endif
707   pc->plugin->env->receive (ps->peercontext->plugin->env->cls,
708                             &pc->identity,
709                             message, 1, ps,
710                             NULL,
711                             0);
712 }
713
714 /**
715  * Check if ip is allowed to connect.
716  */
717 static int
718 mhd_accept_cb (void *cls,
719                       const struct sockaddr *addr, socklen_t addr_len)
720 {
721 #if 0
722   struct Plugin *plugin = cls;
723 #endif
724   /* Every connection is accepted, nothing more to do here */
725   return MHD_YES;
726 }
727
728 int mhd_send_callback (void *cls, uint64_t pos, char *buf, int max)
729 {
730   int bytes_read = 0;
731
732   struct Session * ps = cls;
733   struct HTTP_PeerContext * pc;
734   struct HTTP_Message * msg;
735
736   GNUNET_assert (ps!=NULL);
737   pc = ps->peercontext;
738   msg = ps->pending_msgs_tail;
739   if (ps->send_force_disconnect==GNUNET_YES)
740   {
741 #if DEBUG_CONNECTIONS
742     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound forced to disconnect\n",ps);
743 #endif
744     return -1;
745   }
746
747   if (msg!=NULL)
748   {
749     if ((msg->size-msg->pos) <= max)
750     {
751       memcpy(buf,&msg->buf[msg->pos],(msg->size-msg->pos));
752       bytes_read = msg->size-msg->pos;
753       msg->pos+=(msg->size-msg->pos);
754     }
755     else
756     {
757       memcpy(buf,&msg->buf[msg->pos],max);
758       msg->pos+=max;
759       bytes_read = max;
760     }
761
762     if (msg->pos==msg->size)
763     {
764       if (NULL!=msg->transmit_cont)
765         msg->transmit_cont (msg->transmit_cont_cls,&pc->identity,GNUNET_OK);
766       remove_http_message(ps,msg);
767     }
768   }
769   return bytes_read;
770 }
771
772 /**
773  * Process GET or PUT request received via MHD.  For
774  * GET, queue response that will send back our pending
775  * messages.  For PUT, process incoming data and send
776  * to GNUnet core.  In either case, check if a session
777  * already exists and create a new one if not.
778  */
779 static int
780 mdh_access_cb (void *cls,
781                        struct MHD_Connection *mhd_connection,
782                        const char *url,
783                        const char *method,
784                        const char *version,
785                        const char *upload_data,
786                        size_t * upload_data_size, void **httpSessionCache)
787 {
788   struct Plugin *plugin = cls;
789   struct MHD_Response *response;
790   const union MHD_ConnectionInfo * conn_info;
791
792   struct sockaddr_in  *addrin;
793   struct sockaddr_in6 *addrin6;
794
795   char address[INET6_ADDRSTRLEN+14];
796   struct GNUNET_PeerIdentity pi_in;
797   size_t id_num = 0;
798
799   struct IPv4HttpAddress ipv4addr;
800   struct IPv6HttpAddress ipv6addr;
801
802   struct HTTP_PeerContext *pc;
803   struct Session *ps = NULL;
804   struct Session *ps_tmp = NULL;
805
806   int res = GNUNET_NO;
807   int send_error_to_client;
808   void * addr;
809   size_t addr_len;
810
811   GNUNET_assert(cls !=NULL);
812   send_error_to_client = GNUNET_NO;
813
814   if (NULL == *httpSessionCache)
815   {
816     /* check url for peer identity , if invalid send HTTP 404*/
817     size_t len = strlen(&url[1]);
818     char * peer = GNUNET_malloc(104+1);
819
820     if ((len>104) && (url[104]==';'))
821     {
822         char * id = GNUNET_malloc((len-104)+1);
823         strcpy(id,&url[105]);
824         memcpy(peer,&url[1],103);
825         peer[103] = '\0';
826         id_num = strtoul ( id, NULL , 10);
827         GNUNET_free(id);
828     }
829     res = GNUNET_CRYPTO_hash_from_string (peer, &(pi_in.hashPubKey));
830     GNUNET_free(peer);
831     if ( GNUNET_SYSERR == res )
832     {
833       response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
834       res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
835       MHD_destroy_response (response);
836 #if DEBUG_CONNECTIONS
837       if (res == MHD_YES)
838         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident, sent HTTP 1.1/404\n");
839       else
840         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident, could not send error\n");
841 #endif
842       return res;
843     }
844   }
845   else
846   {
847     ps = *httpSessionCache;
848     pc = ps->peercontext;
849   }
850
851   if (NULL == *httpSessionCache)
852   {
853     /* get peer context */
854     pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &pi_in.hashPubKey);
855     /* Peer unknown */
856     if (pc==NULL)
857     {
858       pc = GNUNET_malloc(sizeof (struct HTTP_PeerContext));
859       pc->plugin = plugin;
860       pc->session_id_counter=1;
861       pc->last_session = NULL;
862       memcpy(&pc->identity, &pi_in, sizeof(struct GNUNET_PeerIdentity));
863       GNUNET_CONTAINER_multihashmap_put(plugin->peers, &pc->identity.hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
864       GNUNET_STATISTICS_update (plugin->env->stats,
865                             gettext_noop ("# HTTP peers active"),
866                             1,
867                             GNUNET_NO);
868     }
869
870     conn_info = MHD_get_connection_info(mhd_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS );
871     /* Incoming IPv4 connection */
872     if ( AF_INET == conn_info->client_addr->sin_family)
873     {
874       addrin = conn_info->client_addr;
875       inet_ntop(addrin->sin_family, &(addrin->sin_addr),address,INET_ADDRSTRLEN);
876       memcpy(&ipv4addr.ipv4_addr,&(addrin->sin_addr),sizeof(struct in_addr));
877       ipv4addr.u_port = addrin->sin_port;
878       addr = &ipv4addr;
879       addr_len = sizeof(struct IPv4HttpAddress);
880     }
881     /* Incoming IPv6 connection */
882     if ( AF_INET6 == conn_info->client_addr->sin_family)
883     {
884       addrin6 = (struct sockaddr_in6 *) conn_info->client_addr;
885       inet_ntop(addrin6->sin6_family, &(addrin6->sin6_addr),address,INET6_ADDRSTRLEN);
886       memcpy(&ipv6addr.ipv6_addr,&(addrin6->sin6_addr),sizeof(struct in6_addr));
887       ipv6addr.u6_port = addrin6->sin6_port;
888       addr = &ipv6addr;
889       addr_len = sizeof(struct IPv6HttpAddress);
890     }
891
892     ps = NULL;
893     /* only inbound sessions here */
894
895     ps_tmp = pc->head;
896     while (ps_tmp!=NULL)
897     {
898       if ((ps_tmp->direction==INBOUND) && (ps_tmp->session_id == id_num) && (id_num!=0))
899       {
900         if ((ps_tmp->recv_force_disconnect!=GNUNET_YES) && (ps_tmp->send_force_disconnect!=GNUNET_YES))
901         ps=ps_tmp;
902         break;
903       }
904       ps_tmp=ps_tmp->next;
905     }
906
907     if (ps==NULL)
908     {
909       ps = GNUNET_malloc(sizeof (struct Session));
910       ps->addr = GNUNET_malloc(addr_len);
911       memcpy(ps->addr,addr,addr_len);
912       ps->addrlen = addr_len;
913       ps->direction=INBOUND;
914       ps->pending_msgs_head = NULL;
915       ps->pending_msgs_tail = NULL;
916       ps->send_connected=GNUNET_NO;
917       ps->send_active=GNUNET_NO;
918       ps->recv_connected=GNUNET_NO;
919       ps->recv_active=GNUNET_NO;
920       ps->peercontext=pc;
921       ps->session_id =id_num;
922       ps->url = create_url (plugin, ps->addr, ps->addrlen, ps->session_id);
923       GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps);
924       GNUNET_STATISTICS_update (plugin->env->stats,
925                             gettext_noop ("# HTTPS inbound sessions for peers active"),
926                             1,
927                             GNUNET_NO);
928     }
929
930     *httpSessionCache = ps;
931     if (ps->msgtok==NULL)
932       ps->msgtok = GNUNET_SERVER_mst_create (&mhd_write_mst_cb, ps);
933 #if DEBUG_HTTPS
934     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: HTTPS Daemon has new an incoming `%s' request from peer `%s' (`%s')\n",
935                 ps,
936                 method,
937                 GNUNET_i2s(&pc->identity),
938                 http_plugin_address_to_string(NULL, ps->addr, ps->addrlen));
939 #endif
940   }
941
942   /* Is it a PUT or a GET request */
943   if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
944   {
945     if (ps->recv_force_disconnect == GNUNET_YES)
946     {
947 #if DEBUG_CONNECTIONS
948       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound connection was forced to disconnect\n",ps);
949 #endif
950       ps->recv_active = GNUNET_NO;
951       return MHD_NO;
952     }
953     if ((*upload_data_size == 0) && (ps->recv_active==GNUNET_NO))
954     {
955       ps->recv_endpoint = mhd_connection;
956       ps->recv_connected = GNUNET_YES;
957       ps->recv_active = GNUNET_YES;
958       ps->recv_force_disconnect = GNUNET_NO;
959 #if DEBUG_CONNECTIONS
960       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound PUT connection connected\n",ps);
961 #endif
962       return MHD_YES;
963     }
964
965     /* Transmission of all data complete */
966     if ((*upload_data_size == 0) && (ps->recv_active == GNUNET_YES))
967     {
968       response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
969       res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
970 #if DEBUG_CONNECTIONS
971       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: Sent HTTP/1.1: 200 OK as PUT Response\n",ps);
972 #endif
973       MHD_destroy_response (response);
974       ps->recv_active=GNUNET_NO;
975       return MHD_YES;
976     }
977
978     /* Recieving data */
979     if ((*upload_data_size > 0) && (ps->recv_active == GNUNET_YES))
980     {
981       res = GNUNET_SERVER_mst_receive(ps->msgtok, ps, upload_data,*upload_data_size, GNUNET_NO, GNUNET_NO);
982       (*upload_data_size) = 0;
983       return MHD_YES;
984     }
985     else
986       return MHD_NO;
987   }
988   if ( 0 == strcmp (MHD_HTTP_METHOD_GET, method) )
989   {
990     if (ps->send_force_disconnect == GNUNET_YES)
991     {
992 #if DEBUG_CONNECTIONS
993       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound connection was  forced to disconnect\n",ps);
994 #endif
995       ps->send_active = GNUNET_NO;
996       return MHD_NO;
997     }
998           ps->send_connected = GNUNET_YES;
999           ps->send_active = GNUNET_YES;
1000           ps->send_endpoint = mhd_connection;
1001           ps->send_force_disconnect = GNUNET_NO;
1002 #if DEBUG_CONNECTIONS
1003           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound GET connection connected\n",ps);
1004 #endif
1005           response = MHD_create_response_from_callback(-1,32 * 1024, &mhd_send_callback, ps, NULL);
1006           res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1007           MHD_destroy_response (response);
1008           return MHD_YES;
1009   }
1010   return MHD_NO;
1011 }
1012
1013 /**
1014  * Function that queries MHD's select sets and
1015  * starts the task waiting for them.
1016  */
1017 static GNUNET_SCHEDULER_TaskIdentifier
1018 http_server_daemon_prepare (void * cls, struct MHD_Daemon *daemon_handle)
1019 {
1020   struct Plugin *plugin = cls;
1021   GNUNET_SCHEDULER_TaskIdentifier ret;
1022   fd_set rs;
1023   fd_set ws;
1024   fd_set es;
1025   struct GNUNET_NETWORK_FDSet *wrs;
1026   struct GNUNET_NETWORK_FDSet *wws;
1027   struct GNUNET_NETWORK_FDSet *wes;
1028   int max;
1029   unsigned long long timeout;
1030   int haveto;
1031   struct GNUNET_TIME_Relative tv;
1032
1033   GNUNET_assert(cls !=NULL);
1034   ret = GNUNET_SCHEDULER_NO_TASK;
1035   FD_ZERO(&rs);
1036   FD_ZERO(&ws);
1037   FD_ZERO(&es);
1038   wrs = GNUNET_NETWORK_fdset_create ();
1039   wes = GNUNET_NETWORK_fdset_create ();
1040   wws = GNUNET_NETWORK_fdset_create ();
1041   max = -1;
1042   GNUNET_assert (MHD_YES ==
1043                  MHD_get_fdset (daemon_handle,
1044                                 &rs,
1045                                 &ws,
1046                                 &es,
1047                                 &max));
1048   haveto = MHD_get_timeout (daemon_handle, &timeout);
1049   if (haveto == MHD_YES)
1050     tv.value = (uint64_t) timeout;
1051   else
1052     tv = GNUNET_TIME_UNIT_FOREVER_REL;
1053   GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max);
1054   GNUNET_NETWORK_fdset_copy_native (wws, &ws, max);
1055   GNUNET_NETWORK_fdset_copy_native (wes, &es, max);
1056   if (daemon_handle == plugin->http_server_daemon_v4)
1057   {
1058         if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
1059         {
1060                 GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v4);
1061                 plugin->http_server_daemon_v4 = GNUNET_SCHEDULER_NO_TASK;
1062         }
1063
1064     ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
1065                                        GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1066                                        GNUNET_SCHEDULER_NO_TASK,
1067                                        tv,
1068                                        wrs,
1069                                        wws,
1070                                        &http_server_daemon_v4_run,
1071                                        plugin);
1072   }
1073   if (daemon_handle == plugin->http_server_daemon_v6)
1074   {
1075         if (plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
1076         {
1077                 GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v6);
1078                 plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
1079         }
1080
1081     ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
1082                                        GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1083                                        GNUNET_SCHEDULER_NO_TASK,
1084                                        tv,
1085                                        wrs,
1086                                        wws,
1087                                        &http_server_daemon_v6_run,
1088                                        plugin);
1089   }
1090   GNUNET_NETWORK_fdset_destroy (wrs);
1091   GNUNET_NETWORK_fdset_destroy (wws);
1092   GNUNET_NETWORK_fdset_destroy (wes);
1093   return ret;
1094 }
1095
1096 /**
1097  * Call MHD to process pending requests and then go back
1098  * and schedule the next run.
1099  */
1100 static void http_server_daemon_v4_run (void *cls,
1101                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1102 {
1103   struct Plugin *plugin = cls;
1104
1105   GNUNET_assert(cls !=NULL);
1106   plugin->http_server_task_v4 = GNUNET_SCHEDULER_NO_TASK;
1107
1108   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1109     return;
1110
1111   GNUNET_assert (MHD_YES == MHD_run (plugin->http_server_daemon_v4));
1112   plugin->http_server_task_v4 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v4);
1113   return;
1114 }
1115
1116
1117 /**
1118  * Call MHD to process pending requests and then go back
1119  * and schedule the next run.
1120  */
1121 static void http_server_daemon_v6_run (void *cls,
1122                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1123 {
1124   struct Plugin *plugin = cls;
1125
1126   GNUNET_assert(cls !=NULL);
1127   plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
1128
1129   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1130     return;
1131
1132   GNUNET_assert (MHD_YES == MHD_run (plugin->http_server_daemon_v6));
1133   plugin->http_server_task_v6 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v6);
1134   return;
1135 }
1136
1137 static size_t curl_get_header_cb( void *ptr, size_t size, size_t nmemb, void *stream)
1138 {
1139   struct Session * ps = stream;
1140
1141   long http_result = 0;
1142   int res;
1143   /* Getting last http result code */
1144   if (ps->recv_connected==GNUNET_NO)
1145   {
1146     GNUNET_assert(NULL!=ps);
1147     res = curl_easy_getinfo(ps->recv_endpoint, CURLINFO_RESPONSE_CODE, &http_result);
1148     if (CURLE_OK == res)
1149     {
1150       if (http_result == 200)
1151       {
1152         ps->recv_connected = GNUNET_YES;
1153         ps->recv_active = GNUNET_YES;
1154 #if DEBUG_CONNECTIONS
1155         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: connected to recieve data\n",ps);
1156 #endif
1157         // Calling send_check_connections again since receive is established
1158         send_check_connections (ps->peercontext->plugin, ps);
1159       }
1160     }
1161   }
1162
1163 #if DEBUG_CURL
1164   char * tmp;
1165   size_t len = size * nmemb;
1166
1167   tmp = NULL;
1168   if ((size * nmemb) < SIZE_MAX)
1169     tmp = GNUNET_malloc (len+1);
1170
1171   if ((tmp != NULL) && (len > 0))
1172   {
1173     memcpy(tmp,ptr,len);
1174     if (len>=2)
1175     {
1176       if (tmp[len-2] == 13)
1177         tmp[len-2]= '\0';
1178     }
1179 #if DEBUG_CURL
1180     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: Header: %s\n",ps,tmp);
1181 #endif
1182   }
1183   if (NULL != tmp)
1184     GNUNET_free (tmp);
1185 #endif
1186
1187   return size * nmemb;
1188 }
1189
1190 static size_t curl_put_header_cb( void *ptr, size_t size, size_t nmemb, void *stream)
1191 {
1192   struct Session * ps = stream;
1193
1194   char * tmp;
1195   size_t len = size * nmemb;
1196   long http_result = 0;
1197   int res;
1198
1199   /* Getting last http result code */
1200   GNUNET_assert(NULL!=ps);
1201   res = curl_easy_getinfo(ps->send_endpoint, CURLINFO_RESPONSE_CODE, &http_result);
1202   if (CURLE_OK == res)
1203   {
1204     if ((http_result == 100) && (ps->send_connected==GNUNET_NO))
1205     {
1206       ps->send_connected = GNUNET_YES;
1207       ps->send_active = GNUNET_YES;
1208 #if DEBUG_CONNECTIONS
1209       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: connected to send data\n",ps);
1210 #endif
1211     }
1212     if ((http_result == 200) && (ps->send_connected==GNUNET_YES))
1213     {
1214       ps->send_connected = GNUNET_NO;
1215       ps->send_active = GNUNET_NO;
1216 #if DEBUG_CONNECTIONS
1217       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: sending disconnected\n",ps);
1218 #endif
1219     }
1220   }
1221
1222   tmp = NULL;
1223   if ((size * nmemb) < SIZE_MAX)
1224     tmp = GNUNET_malloc (len+1);
1225
1226   if ((tmp != NULL) && (len > 0))
1227   {
1228     memcpy(tmp,ptr,len);
1229     if (len>=2)
1230     {
1231       if (tmp[len-2] == 13)
1232         tmp[len-2]= '\0';
1233     }
1234   }
1235   if (NULL != tmp)
1236     GNUNET_free (tmp);
1237
1238   return size * nmemb;
1239 }
1240
1241 /**
1242  * Callback method used with libcurl
1243  * Method is called when libcurl needs to read data during sending
1244  * @param stream pointer where to write data
1245  * @param size size of an individual element
1246  * @param nmemb count of elements that can be written to the buffer
1247  * @param ptr source pointer, passed to the libcurl handle
1248  * @return bytes written to stream
1249  */
1250 static size_t curl_send_cb(void *stream, size_t size, size_t nmemb, void *ptr)
1251 {
1252   struct Session * ps = ptr;
1253   struct HTTP_Message * msg = ps->pending_msgs_tail;
1254   size_t bytes_sent;
1255   size_t len;
1256
1257   if (ps->send_active == GNUNET_NO)
1258         return CURL_READFUNC_PAUSE;
1259
1260
1261   if ((ps->pending_msgs_tail == NULL) && (ps->send_active == GNUNET_YES))
1262   {
1263 #if DEBUG_CONNECTIONS
1264     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: No Message to send, pausing connection\n",ps);
1265 #endif
1266     ps->send_active = GNUNET_NO;
1267     return CURL_READFUNC_PAUSE;
1268   }
1269
1270   msg = ps->pending_msgs_tail;
1271   /* data to send */
1272   if (msg->pos < msg->size)
1273   {
1274     /* data fit in buffer */
1275     if ((msg->size - msg->pos) <= (size * nmemb))
1276     {
1277       len = (msg->size - msg->pos);
1278       memcpy(stream, &msg->buf[msg->pos], len);
1279       msg->pos += len;
1280       bytes_sent = len;
1281     }
1282     else
1283     {
1284       len = size*nmemb;
1285       memcpy(stream, &msg->buf[msg->pos], len);
1286       msg->pos += len;
1287       bytes_sent = len;
1288     }
1289   }
1290   /* no data to send */
1291   else
1292   {
1293     bytes_sent = 0;
1294   }
1295
1296   if ( msg->pos == msg->size)
1297   {
1298 #if DEBUG_CONNECTIONS
1299     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: Message with %u bytes sent, removing message from queue \n",ps, msg->pos);
1300 #endif
1301     /* Calling transmit continuation  */
1302     if (( NULL != ps->pending_msgs_tail) && (NULL != ps->pending_msgs_tail->transmit_cont))
1303       msg->transmit_cont (ps->pending_msgs_tail->transmit_cont_cls,&(ps->peercontext)->identity,GNUNET_OK);
1304     remove_http_message(ps, msg);
1305   }
1306   return bytes_sent;
1307 }
1308
1309 static void curl_receive_mst_cb  (void *cls,
1310                                 void *client,
1311                                 const struct GNUNET_MessageHeader *message)
1312 {
1313   struct Session *ps  = cls;
1314   struct HTTP_PeerContext *pc = ps->peercontext;
1315   GNUNET_assert(ps != NULL);
1316   GNUNET_assert(pc != NULL);
1317 #if DEBUG_HTTPS
1318   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1319               "Connection %X: Forwarding message to transport service, type %u and size %u from `%s' (`%s')\n",
1320               ps,
1321               ntohs(message->type),
1322               ntohs(message->size),
1323               GNUNET_i2s(&(pc->identity)),http_plugin_address_to_string(NULL,ps->addr,ps->addrlen));
1324 #endif
1325   pc->plugin->env->receive (pc->plugin->env->cls,
1326                             &pc->identity,
1327                             message, 1, ps,
1328                             ps->addr,
1329                             ps->addrlen);
1330 }
1331
1332
1333 /**
1334 * Callback method used with libcurl
1335 * Method is called when libcurl needs to write data during sending
1336 * @param stream pointer where to write data
1337 * @param size size of an individual element
1338 * @param nmemb count of elements that can be written to the buffer
1339 * @param ptr destination pointer, passed to the libcurl handle
1340 * @return bytes read from stream
1341 */
1342 static size_t curl_receive_cb( void *stream, size_t size, size_t nmemb, void *ptr)
1343 {
1344   struct Session * ps = ptr;
1345 #if DEBUG_CONNECTIONS
1346   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: %u bytes received\n",ps, size*nmemb);
1347 #endif
1348   GNUNET_SERVER_mst_receive(ps->msgtok, ps, stream, size*nmemb, GNUNET_NO, GNUNET_NO);
1349   return (size * nmemb);
1350
1351 }
1352
1353 static void curl_perform (void *cls,
1354              const struct GNUNET_SCHEDULER_TaskContext *tc)
1355 {
1356   struct Plugin *plugin = cls;
1357   static unsigned int handles_last_run;
1358   int running;
1359   struct CURLMsg *msg;
1360   CURLMcode mret;
1361   struct Session *ps = NULL;
1362   struct HTTP_PeerContext *pc = NULL;
1363   struct HTTP_Message * cur_msg = NULL;
1364   long http_result;
1365   char * tmp;
1366
1367   GNUNET_assert(cls !=NULL);
1368
1369   plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK;
1370   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1371     return;
1372
1373   do
1374     {
1375       running = 0;
1376       mret = curl_multi_perform (plugin->multi_handle, &running);
1377       if ((running < handles_last_run) && (running>0))
1378         {
1379           do
1380             {
1381
1382               msg = curl_multi_info_read (plugin->multi_handle, &running);
1383               if (running == 0)
1384                   break;
1385               /* get session for affected curl handle */
1386               GNUNET_assert ( msg->easy_handle != NULL );
1387               curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &tmp);
1388               ps = (struct Session *) tmp;
1389               GNUNET_assert ( ps != NULL );
1390               pc = ps->peercontext;
1391               GNUNET_assert ( pc != NULL );
1392               switch (msg->msg)
1393                 {
1394
1395                 case CURLMSG_DONE:
1396                   if ( (msg->data.result != CURLE_OK) &&
1397                        (msg->data.result != CURLE_GOT_NOTHING) )
1398                   {
1399                     /* sending msg failed*/
1400                     if (msg->easy_handle == ps->send_endpoint)
1401                     {
1402 #if DEBUG_CONNECTIONS
1403                       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1404                                  _("Connection %X: HTTPS PUT to peer `%s' (`%s') failed: `%s' `%s'\n"),
1405                                  ps,
1406                                  GNUNET_i2s(&pc->identity),
1407                                  http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
1408                                  "curl_multi_perform",
1409                                  curl_easy_strerror (msg->data.result));
1410 #endif
1411                       ps->send_connected = GNUNET_NO;
1412                       ps->send_active = GNUNET_NO;
1413                       curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint);
1414                       //curl_easy_cleanup(ps->send_endpoint);
1415                       //ps->send_endpoint=NULL;
1416                       cur_msg = ps->pending_msgs_tail;
1417                       if (( NULL != cur_msg) && ( NULL != cur_msg->transmit_cont))
1418                         cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_SYSERR);
1419                     }
1420                     /* GET connection failed */
1421                     if (msg->easy_handle == ps->recv_endpoint)
1422                     {
1423 #if DEBUG_CONNECTIONS
1424                       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1425                            _("Connection %X: HTTPS GET to peer `%s' (`%s') failed: `%s' `%s'\n"),
1426                            ps,
1427                            GNUNET_i2s(&pc->identity),
1428                            http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
1429                            "curl_multi_perform",
1430                            curl_easy_strerror (msg->data.result));
1431 #endif
1432                       ps->recv_connected = GNUNET_NO;
1433                       ps->recv_active = GNUNET_NO;
1434                       curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint);
1435                       //curl_easy_cleanup(ps->recv_endpoint);
1436                       //ps->recv_endpoint=NULL;
1437                     }
1438                   }
1439                   else
1440                   {
1441                     if (msg->easy_handle == ps->send_endpoint)
1442                     {
1443                       GNUNET_assert (CURLE_OK == curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &http_result));
1444 #if DEBUG_CONNECTIONS
1445                       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1446                                   "Connection %X: HTTPS PUT connection to peer `%s' (`%s') was closed with HTTP code %u\n",
1447                                    ps,
1448                                    GNUNET_i2s(&pc->identity),
1449                                    http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
1450                                    http_result);
1451 #endif
1452                       /* Calling transmit continuation  */
1453                       cur_msg = ps->pending_msgs_tail;
1454                       if (( NULL != cur_msg) && (NULL != cur_msg->transmit_cont))
1455                       {
1456                         /* HTTP 1xx : Last message before here was informational */
1457                         if ((http_result >=100) && (http_result < 200))
1458                           cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_OK);
1459                         /* HTTP 2xx: successful operations */
1460                         if ((http_result >=200) && (http_result < 300))
1461                           cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_OK);
1462                         /* HTTP 3xx..5xx: error */
1463                         if ((http_result >=300) && (http_result < 600))
1464                           cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_SYSERR);
1465                       }
1466                       ps->send_connected = GNUNET_NO;
1467                       ps->send_active = GNUNET_NO;
1468                       curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint);
1469                       //curl_easy_cleanup(ps->send_endpoint);
1470                       //ps->send_endpoint =NULL;
1471                     }
1472                     if (msg->easy_handle == ps->recv_endpoint)
1473                     {
1474 #if DEBUG_CONNECTIONS
1475                       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1476                                   "Connection %X: HTTP GET connection to peer `%s' (`%s') was closed with HTTP code %u\n",
1477                                    ps,
1478                                    GNUNET_i2s(&pc->identity),
1479                                    http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
1480                                    http_result);
1481 #endif
1482                       ps->recv_connected = GNUNET_NO;
1483                       ps->recv_active = GNUNET_NO;
1484                       curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint);
1485                       //curl_easy_cleanup(ps->recv_endpoint);
1486                       //ps->recv_endpoint=NULL;
1487                     }
1488                   }
1489                   if ((ps->recv_connected == GNUNET_NO) && (ps->send_connected == GNUNET_NO))
1490                     remove_session (pc, ps, GNUNET_YES, GNUNET_SYSERR);
1491                   break;
1492                 default:
1493                   break;
1494                 }
1495
1496             }
1497           while ( (running > 0) );
1498         }
1499       handles_last_run = running;
1500     }
1501   while (mret == CURLM_CALL_MULTI_PERFORM);
1502   curl_schedule(plugin);
1503 }
1504
1505
1506 /**
1507  * Function setting up file descriptors and scheduling task to run
1508  * @param ses session to send data to
1509  * @return GNUNET_SYSERR for hard failure, GNUNET_OK for ok
1510  */
1511 static void
1512 http_plugin_disconnect (void *cls,
1513                             const struct GNUNET_PeerIdentity *target)
1514 {
1515
1516
1517   struct Plugin *plugin = cls;
1518   struct HTTP_PeerContext *pc = NULL;
1519   struct Session *ps = NULL;
1520   //struct Session *tmp = NULL;
1521
1522   pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &target->hashPubKey);
1523   if (pc==NULL)
1524     return;
1525   ps = pc->head;
1526
1527   while (ps!=NULL)
1528   {
1529     /* Telling transport that session is getting disconnected */
1530     plugin->env->session_end(plugin, target, ps);
1531     if (ps->direction==OUTBOUND)
1532     {
1533       if (ps->send_endpoint!=NULL)
1534       {
1535         //GNUNET_assert(CURLM_OK == curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint));
1536         //curl_easy_cleanup(ps->send_endpoint);
1537         //ps->send_endpoint=NULL;
1538         ps->send_force_disconnect = GNUNET_YES;
1539       }
1540       if (ps->recv_endpoint!=NULL)
1541       {
1542        //GNUNET_assert(CURLM_OK == curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint));
1543        //curl_easy_cleanup(ps->recv_endpoint);
1544        //ps->recv_endpoint=NULL;
1545        ps->recv_force_disconnect = GNUNET_YES;
1546       }
1547     }
1548
1549     if (ps->direction==INBOUND)
1550     {
1551       ps->recv_force_disconnect = GNUNET_YES;
1552       ps->send_force_disconnect = GNUNET_YES;
1553     }
1554
1555     while (ps->pending_msgs_head!=NULL)
1556     {
1557       remove_http_message(ps, ps->pending_msgs_head);
1558     }
1559     ps->recv_active = GNUNET_NO;
1560     ps->send_active = GNUNET_NO;
1561     ps=ps->next;
1562   }
1563 }
1564
1565
1566 static int curl_schedule(void *cls)
1567 {
1568   struct Plugin *plugin = cls;
1569   fd_set rs;
1570   fd_set ws;
1571   fd_set es;
1572   int max;
1573   struct GNUNET_NETWORK_FDSet *grs;
1574   struct GNUNET_NETWORK_FDSet *gws;
1575   long to;
1576   CURLMcode mret;
1577
1578   GNUNET_assert(cls !=NULL);
1579
1580   /* Cancel previous scheduled task */
1581   if (plugin->http_curl_task !=  GNUNET_SCHEDULER_NO_TASK)
1582   {
1583           GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_curl_task);
1584           plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK;
1585   }
1586   max = -1;
1587   FD_ZERO (&rs);
1588   FD_ZERO (&ws);
1589   FD_ZERO (&es);
1590   mret = curl_multi_fdset (plugin->multi_handle, &rs, &ws, &es, &max);
1591   if (mret != CURLM_OK)
1592     {
1593       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1594                   _("%s failed at %s:%d: `%s'\n"),
1595                   "curl_multi_fdset", __FILE__, __LINE__,
1596                   curl_multi_strerror (mret));
1597       return GNUNET_SYSERR;
1598     }
1599   mret = curl_multi_timeout (plugin->multi_handle, &to);
1600   if (mret != CURLM_OK)
1601     {
1602       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1603                   _("%s failed at %s:%d: `%s'\n"),
1604                   "curl_multi_timeout", __FILE__, __LINE__,
1605                   curl_multi_strerror (mret));
1606       return GNUNET_SYSERR;
1607     }
1608
1609   grs = GNUNET_NETWORK_fdset_create ();
1610   gws = GNUNET_NETWORK_fdset_create ();
1611   GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
1612   GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
1613   plugin->http_curl_task = GNUNET_SCHEDULER_add_select (plugin->env->sched,
1614                                    GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1615                                    GNUNET_SCHEDULER_NO_TASK,
1616                                    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 0),
1617                                    grs,
1618                                    gws,
1619                                    &curl_perform,
1620                                    plugin);
1621   GNUNET_NETWORK_fdset_destroy (gws);
1622   GNUNET_NETWORK_fdset_destroy (grs);
1623   return GNUNET_OK;
1624 }
1625
1626 /**
1627  * Function setting up curl handle and selecting message to send
1628  * @param cls plugin
1629  * @param ses session to send data to
1630  * @param con connection
1631  * @return GNUNET_SYSERR on failure, GNUNET_NO if connecting, GNUNET_YES if ok
1632  */
1633 static ssize_t send_check_connections (void *cls, struct Session *ps)
1634 {
1635   struct Plugin *plugin = cls;
1636   CURLMcode mret;
1637   struct HTTP_Message * msg;
1638
1639   struct GNUNET_TIME_Relative timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
1640
1641   GNUNET_assert(cls !=NULL);
1642
1643   if (ps->direction == OUTBOUND)
1644   {
1645     /* RECV DIRECTION */
1646     /* Check if session is connected to receive data, otherwise connect to peer */
1647     if (ps->recv_connected == GNUNET_NO)
1648     {
1649         int fresh = GNUNET_NO;
1650         if (ps->recv_endpoint == NULL)
1651         {
1652             fresh = GNUNET_YES;
1653                 ps->recv_endpoint = curl_easy_init();
1654         }
1655 #if DEBUG_CURL
1656         curl_easy_setopt(ps->recv_endpoint, CURLOPT_VERBOSE, 1L);
1657 #endif
1658         curl_easy_setopt(ps->recv_endpoint, CURLOPT_URL, ps->url);
1659         curl_easy_setopt (ps->recv_endpoint, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
1660         //curl_easy_setopt (ps->recv_endpoint, CURLOPT_SSL_CIPHER_LIST, cipher_suite);
1661                 curl_easy_setopt(ps->recv_endpoint, CURLOPT_SSL_VERIFYPEER, 0);
1662                 curl_easy_setopt(ps->recv_endpoint, CURLOPT_SSL_VERIFYHOST, 0);
1663         curl_easy_setopt(ps->recv_endpoint, CURLOPT_HEADERFUNCTION, &curl_get_header_cb);
1664         curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEHEADER, ps);
1665         curl_easy_setopt(ps->recv_endpoint, CURLOPT_READFUNCTION, curl_send_cb);
1666         curl_easy_setopt(ps->recv_endpoint, CURLOPT_READDATA, ps);
1667         curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEFUNCTION, curl_receive_cb);
1668         curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEDATA, ps);
1669         curl_easy_setopt(ps->recv_endpoint, CURLOPT_TIMEOUT, (long) timeout.value);
1670         curl_easy_setopt(ps->recv_endpoint, CURLOPT_PRIVATE, ps);
1671         curl_easy_setopt(ps->recv_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
1672         curl_easy_setopt(ps->recv_endpoint, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
1673
1674         if (fresh==GNUNET_YES)
1675         {
1676                         mret = curl_multi_add_handle(plugin->multi_handle, ps->recv_endpoint);
1677                         if (mret != CURLM_OK)
1678                         {
1679                           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1680                                                   _("Connection: %X: %s failed at %s:%d: `%s'\n"),
1681                                                   ps,
1682                                                   "curl_multi_add_handle", __FILE__, __LINE__,
1683                                                   curl_multi_strerror (mret));
1684                           return GNUNET_SYSERR;
1685                         }
1686         }
1687         if (curl_schedule (plugin) == GNUNET_SYSERR)
1688         {
1689 #if DEBUG_CONNECTIONS
1690         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: could not schedule curl task\n",ps);
1691 #endif
1692                 return GNUNET_SYSERR;
1693         }
1694 #if DEBUG_CONNECTIONS
1695         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound not connected, initiating connection\n",ps);
1696 #endif
1697     }
1698
1699     /* waiting for receive direction */
1700     if (ps->recv_connected==GNUNET_NO)
1701       return GNUNET_NO;
1702
1703     /* SEND DIRECTION */
1704     /* Check if session is connected to send data, otherwise connect to peer */
1705     if ((ps->send_connected == GNUNET_YES) && (ps->send_endpoint!= NULL))
1706     {
1707       if (ps->send_active == GNUNET_YES)
1708       {
1709 #if DEBUG_CONNECTIONS
1710         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound active, enqueueing message\n",ps);
1711 #endif
1712         return GNUNET_YES;
1713       }
1714       if (ps->send_active == GNUNET_NO)
1715       {
1716 #if DEBUG_CONNECTIONS
1717         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound paused, unpausing existing connection and enqueueing message\n",ps);
1718 #endif
1719         if (CURLE_OK == curl_easy_pause(ps->send_endpoint,CURLPAUSE_CONT))
1720         {
1721                         ps->send_active=GNUNET_YES;
1722                         return GNUNET_YES;
1723         }
1724         else
1725                 return GNUNET_SYSERR;
1726       }
1727     }
1728     /* not connected, initiate connection */
1729     if (ps->send_connected==GNUNET_NO)
1730     {
1731         int fresh = GNUNET_NO;
1732         if (NULL == ps->send_endpoint)
1733         {
1734                 ps->send_endpoint = curl_easy_init();
1735                 fresh = GNUNET_YES;
1736         }
1737                 GNUNET_assert (ps->send_endpoint != NULL);
1738                 GNUNET_assert (NULL != ps->pending_msgs_tail);
1739 #if DEBUG_CONNECTIONS
1740                 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound not connected, initiating connection\n",ps);
1741 #endif
1742                 ps->send_active = GNUNET_NO;
1743                 msg = ps->pending_msgs_tail;
1744
1745 #if DEBUG_CURL
1746                 curl_easy_setopt(ps->send_endpoint, CURLOPT_VERBOSE, 1L);
1747 #endif
1748                 curl_easy_setopt(ps->send_endpoint, CURLOPT_URL, ps->url);
1749                 curl_easy_setopt(ps->send_endpoint, CURLOPT_PUT, 1L);
1750                 curl_easy_setopt(ps->send_endpoint, CURLOPT_HEADERFUNCTION, &curl_put_header_cb);
1751                 curl_easy_setopt(ps->send_endpoint, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
1752                 curl_easy_setopt(ps->send_endpoint, CURLOPT_SSL_VERIFYPEER, 0);
1753                 curl_easy_setopt(ps->send_endpoint, CURLOPT_SSL_VERIFYHOST, 0);
1754
1755                 curl_easy_setopt(ps->send_endpoint, CURLOPT_WRITEHEADER, ps);
1756                 curl_easy_setopt(ps->send_endpoint, CURLOPT_READFUNCTION, curl_send_cb);
1757                 curl_easy_setopt(ps->send_endpoint, CURLOPT_READDATA, ps);
1758                 curl_easy_setopt(ps->send_endpoint, CURLOPT_WRITEFUNCTION, curl_receive_cb);
1759                 curl_easy_setopt(ps->send_endpoint, CURLOPT_READDATA, ps);
1760                 curl_easy_setopt(ps->send_endpoint, CURLOPT_TIMEOUT, (long) timeout.value);
1761                 curl_easy_setopt(ps->send_endpoint, CURLOPT_PRIVATE, ps);
1762                 curl_easy_setopt(ps->send_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
1763                 curl_easy_setopt(ps->send_endpoint, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
1764
1765                 if (fresh==GNUNET_YES)
1766                 {
1767                         mret = curl_multi_add_handle(plugin->multi_handle, ps->send_endpoint);
1768                         if (mret != CURLM_OK)
1769                         {
1770                           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1771                                                   _("Connection: %X: %s failed at %s:%d: `%s'\n"),
1772                                                   ps,
1773                                                   "curl_multi_add_handle", __FILE__, __LINE__,
1774                                                   curl_multi_strerror (mret));
1775                           return GNUNET_SYSERR;
1776                         }
1777                 }
1778     }
1779     if (curl_schedule (plugin) == GNUNET_SYSERR)
1780         return GNUNET_SYSERR;
1781     return GNUNET_YES;
1782   }
1783   if (ps->direction == INBOUND)
1784   {
1785     GNUNET_assert (NULL != ps->pending_msgs_tail);
1786     if ((ps->recv_connected==GNUNET_YES) && (ps->send_connected==GNUNET_YES) &&
1787         (ps->recv_force_disconnect==GNUNET_NO) && (ps->recv_force_disconnect==GNUNET_NO))
1788         return GNUNET_YES;
1789   }
1790   return GNUNET_SYSERR;
1791 }
1792
1793 static struct Session * send_select_session (void * cls, struct HTTP_PeerContext *pc, const void * addr, size_t addrlen, int force_address, struct Session * session)
1794 {
1795         struct Session * tmp = NULL;
1796         int addr_given = GNUNET_NO;
1797
1798         if ((addr!=NULL) && (addrlen>0))
1799                 addr_given = GNUNET_YES;
1800
1801         if (force_address == GNUNET_YES)
1802         {
1803                 /* check session given as argument */
1804                 if ((session != NULL) && (addr_given == GNUNET_YES))
1805                 {
1806                       if (0 == memcmp(session->addr, addr, addrlen))
1807                       {
1808                         /* connection can not be used, since it is disconnected */
1809                         if ((session->recv_force_disconnect==GNUNET_NO) && (session->send_force_disconnect==GNUNET_NO))
1810                         {
1811 #if DEBUG_SESSION_SELECTION
1812                                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using session passed by transport to send to forced address \n", session);
1813 #endif
1814                                 return session;
1815                         }
1816                       }
1817                 }
1818                 /* check last session used */
1819                 if ((pc->last_session != NULL)&& (addr_given == GNUNET_YES))
1820                 {
1821                       if (0 == memcmp(pc->last_session->addr, addr, addrlen))
1822                       {
1823                         /* connection can not be used, since it is disconnected */
1824                         if ((pc->last_session->recv_force_disconnect==GNUNET_NO) && (pc->last_session->send_force_disconnect==GNUNET_NO))
1825                         {
1826 #if DEBUG_SESSION_SELECTION
1827                                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using last session used to send to forced address \n", pc->last_session);
1828 #endif
1829                                 return pc->last_session;
1830                         }
1831                       }
1832                 }
1833                 /* find session in existing sessions */
1834                 tmp = pc->head;
1835                 while ((tmp!=NULL) && (addr_given == GNUNET_YES))
1836                 {
1837
1838                           if (0 == memcmp(tmp->addr, addr, addrlen))
1839                       {
1840                         /* connection can not be used, since it is disconnected */
1841                         if ((tmp->recv_force_disconnect==GNUNET_NO) && (tmp->send_force_disconnect==GNUNET_NO))
1842                         {
1843 #if DEBUG_SESSION_SELECTION
1844                                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using existing session to send to forced address \n", session);
1845 #endif
1846                                   return session;
1847                         }
1848
1849                       }
1850                           tmp=tmp->next;
1851                 }
1852                 /* no session to use */
1853                 return NULL;
1854         }
1855         if ((force_address == GNUNET_NO) || (force_address == GNUNET_SYSERR))
1856         {
1857                 /* check session given as argument */
1858                 if (session != NULL)
1859                 {
1860                         /* connection can not be used, since it is disconnected */
1861                         if ((session->recv_force_disconnect==GNUNET_NO) && (session->send_force_disconnect==GNUNET_NO))
1862                         {
1863 #if DEBUG_SESSION_SELECTION
1864                                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using session passed by transport to send not-forced address \n", session);
1865 #endif
1866                                   return session;
1867                         }
1868
1869                 }
1870                 /* check last session used */
1871                 if (pc->last_session != NULL)
1872                 {
1873                         /* connection can not be used, since it is disconnected */
1874                         if ((pc->last_session->recv_force_disconnect==GNUNET_NO) && (pc->last_session->send_force_disconnect==GNUNET_NO))
1875                         {
1876 #if DEBUG_SESSION_SELECTION
1877                                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using last session to send to not-forced address \n", pc->last_session);
1878 #endif
1879                                 return pc->last_session;
1880                         }
1881                 }
1882                 /* find session in existing sessions */
1883                 tmp = pc->head;
1884                 while (tmp!=NULL)
1885                 {
1886                         /* connection can not be used, since it is disconnected */
1887                         if ((tmp->recv_force_disconnect==GNUNET_NO) && (tmp->send_force_disconnect==GNUNET_NO))
1888                         {
1889 #if DEBUG_SESSION_SELECTION
1890                                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using existing session to send to not-forced address \n", tmp);
1891 #endif
1892                                 return tmp;
1893                         }
1894                         tmp=tmp->next;
1895                 }
1896                 return NULL;
1897         }
1898         return NULL;
1899 }
1900
1901 /**
1902  * Function that can be used by the transport service to transmit
1903  * a message using the plugin.   Note that in the case of a
1904  * peer disconnecting, the continuation MUST be called
1905  * prior to the disconnect notification itself.  This function
1906  * will be called with this peer's HELLO message to initiate
1907  * a fresh connection to another peer.
1908  *
1909  * @param cls closure
1910  * @param target who should receive this message
1911  * @param msgbuf the message to transmit
1912  * @param msgbuf_size number of bytes in 'msgbuf'
1913  * @param priority how important is the message (most plugins will
1914  *                 ignore message priority and just FIFO)
1915  * @param timeout how long to wait at most for the transmission (does not
1916  *                require plugins to discard the message after the timeout,
1917  *                just advisory for the desired delay; most plugins will ignore
1918  *                this as well)
1919  * @param session which session must be used (or NULL for "any")
1920  * @param addr the address to use (can be NULL if the plugin
1921  *                is "on its own" (i.e. re-use existing TCP connection))
1922  * @param addrlen length of the address in bytes
1923  * @param force_address GNUNET_YES if the plugin MUST use the given address,
1924  *                GNUNET_NO means the plugin may use any other address and
1925  *                GNUNET_SYSERR means that only reliable existing
1926  *                bi-directional connections should be used (regardless
1927  *                of address)
1928  * @param cont continuation to call once the message has
1929  *        been transmitted (or if the transport is ready
1930  *        for the next transmission call; or if the
1931  *        peer disconnected...); can be NULL
1932  * @param cont_cls closure for cont
1933  * @return number of bytes used (on the physical network, with overheads);
1934  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1935  *         and does NOT mean that the message was not transmitted (DV)
1936  */
1937 static ssize_t
1938 http_plugin_send (void *cls,
1939                   const struct GNUNET_PeerIdentity *target,
1940                   const char *msgbuf,
1941                   size_t msgbuf_size,
1942                   unsigned int priority,
1943                   struct GNUNET_TIME_Relative to,
1944                   struct Session *session,
1945                   const void *addr,
1946                   size_t addrlen,
1947                   int force_address,
1948                   GNUNET_TRANSPORT_TransmitContinuation cont,
1949                   void *cont_cls)
1950 {
1951   struct Plugin *plugin = cls;
1952   struct HTTP_Message *msg;
1953   struct HTTP_PeerContext * pc;
1954   struct Session * ps = NULL;
1955
1956   GNUNET_assert(cls !=NULL);
1957
1958 #if DEBUG_HTTPS
1959   char * force = GNUNET_malloc(40);
1960   if (force_address == GNUNET_YES)
1961     strcpy(force,"forced addr.");
1962   if (force_address == GNUNET_NO)
1963     strcpy(force,"any addr.");
1964   if (force_address == GNUNET_SYSERR)
1965     strcpy(force,"reliable bi-direc. address addr.");
1966
1967   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Transport tells me to send %u bytes to `%s' using %s (%s) and session: %X\n",
1968                                       msgbuf_size,
1969                                       GNUNET_i2s(target),
1970                                       force,
1971                                       http_plugin_address_to_string(NULL, addr, addrlen),
1972                                       session);
1973
1974   GNUNET_free(force);
1975 #endif
1976
1977   pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &target->hashPubKey);
1978   /* Peer unknown */
1979   if (pc==NULL)
1980   {
1981     pc = GNUNET_malloc(sizeof (struct HTTP_PeerContext));
1982     pc->plugin = plugin;
1983     pc->session_id_counter=1;
1984     pc->last_session = NULL;
1985     memcpy(&pc->identity, target, sizeof(struct GNUNET_PeerIdentity));
1986     GNUNET_CONTAINER_multihashmap_put(plugin->peers, &pc->identity.hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1987     GNUNET_STATISTICS_update (plugin->env->stats,
1988                             gettext_noop ("# HTTP peers active"),
1989                             1,
1990                             GNUNET_NO);
1991   }
1992
1993   ps = send_select_session (plugin, pc, addr, addrlen, force_address, session);
1994
1995   /* session not existing, but address forced -> creating new session */
1996   if (ps==NULL)
1997   {
1998     if ((addr!=NULL) && (addrlen!=0))
1999     {
2000       ps = GNUNET_malloc(sizeof (struct Session));
2001 #if DEBUG_SESSION_SELECTION
2002       if (force_address == GNUNET_YES)
2003         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No existing connection & forced address: creating new session %X to peer %s\n", ps, GNUNET_i2s(target));
2004       if (force_address != GNUNET_YES)
2005         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No existing connection: creating new session %X to peer %s\n", ps, GNUNET_i2s(target));
2006 #endif
2007       if ((addrlen!=0) && (addr!=NULL))
2008       {
2009       ps->addr = GNUNET_malloc(addrlen);
2010       memcpy(ps->addr,addr,addrlen);
2011       ps->addrlen = addrlen;
2012       }
2013       else
2014       {
2015         ps->addr = NULL;
2016         ps->addrlen = 0;
2017       }
2018       ps->direction=OUTBOUND;
2019       ps->recv_connected = GNUNET_NO;
2020       ps->recv_force_disconnect = GNUNET_NO;
2021       ps->send_connected = GNUNET_NO;
2022       ps->send_force_disconnect = GNUNET_NO;
2023       ps->pending_msgs_head = NULL;
2024       ps->pending_msgs_tail = NULL;
2025       ps->peercontext=pc;
2026       ps->session_id = pc->session_id_counter;
2027       pc->session_id_counter++;
2028       ps->url = create_url (plugin, ps->addr, ps->addrlen, ps->session_id);
2029       if (ps->msgtok == NULL)
2030         ps->msgtok = GNUNET_SERVER_mst_create (&curl_receive_mst_cb, ps);
2031       GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps);
2032 /* FIXME */
2033
2034       GNUNET_STATISTICS_update (plugin->env->stats,
2035                             gettext_noop ("# HTTP outbound sessions for peers active"),
2036                             1,
2037                             GNUNET_NO);
2038     }
2039     else
2040     {
2041 #if DEBUG_HTTPS
2042       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No existing session found & and no address given: no way to send this message to peer `%s'!\n", GNUNET_i2s(target));
2043 #endif
2044       return GNUNET_SYSERR;
2045     }
2046   }
2047
2048   /* create msg */
2049   msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
2050   msg->next = NULL;
2051   msg->size = msgbuf_size;
2052   msg->pos = 0;
2053   msg->buf = (char *) &msg[1];
2054   msg->transmit_cont = cont;
2055   msg->transmit_cont_cls = cont_cls;
2056   memcpy (msg->buf,msgbuf, msgbuf_size);
2057   GNUNET_CONTAINER_DLL_insert(ps->pending_msgs_head,ps->pending_msgs_tail,msg);
2058
2059   if (send_check_connections (plugin, ps) != GNUNET_SYSERR)
2060   {
2061           if (force_address != GNUNET_YES)
2062                   pc->last_session = ps;
2063
2064           if (pc->last_session==NULL)
2065                   pc->last_session = ps;
2066           return msg->size;
2067   }
2068   else
2069           return GNUNET_SYSERR;
2070 }
2071
2072
2073
2074 /**
2075  * Function that can be used to force the plugin to disconnect
2076  * from the given peer and cancel all previous transmissions
2077  * (and their continuationc).
2078  *
2079  * @param cls closure
2080  * @param target peer from which to disconnect
2081  */
2082 /**
2083  * Convert the transports address to a nice, human-readable
2084  * format.
2085  *
2086  * @param cls closure
2087  * @param type name of the transport that generated the address
2088  * @param addr one of the addresses of the host, NULL for the last address
2089  *        the specific address format depends on the transport
2090  * @param addrlen length of the address
2091  * @param numeric should (IP) addresses be displayed in numeric form?
2092  * @param timeout after how long should we give up?
2093  * @param asc function to call on each string
2094  * @param asc_cls closure for asc
2095  */
2096 static void
2097 http_plugin_address_pretty_printer (void *cls,
2098                                         const char *type,
2099                                         const void *addr,
2100                                         size_t addrlen,
2101                                         int numeric,
2102                                         struct GNUNET_TIME_Relative timeout,
2103                                         GNUNET_TRANSPORT_AddressStringCallback
2104                                         asc, void *asc_cls)
2105 {
2106   const struct IPv4HttpAddress *t4;
2107   const struct IPv6HttpAddress *t6;
2108   struct sockaddr_in a4;
2109   struct sockaddr_in6 a6;
2110   char * address;
2111   char * ret;
2112   unsigned int port;
2113   unsigned int res;
2114
2115   GNUNET_assert(cls !=NULL);
2116   if (addrlen == sizeof (struct IPv6HttpAddress))
2117   {
2118     address = GNUNET_malloc (INET6_ADDRSTRLEN);
2119     t6 = addr;
2120     a6.sin6_addr = t6->ipv6_addr;
2121     inet_ntop(AF_INET6, &(a6.sin6_addr),address,INET6_ADDRSTRLEN);
2122     port = ntohs(t6->u6_port);
2123   }
2124   else if (addrlen == sizeof (struct IPv4HttpAddress))
2125   {
2126     address = GNUNET_malloc (INET_ADDRSTRLEN);
2127     t4 = addr;
2128     a4.sin_addr.s_addr =  t4->ipv4_addr;
2129     inet_ntop(AF_INET, &(a4.sin_addr),address,INET_ADDRSTRLEN);
2130     port = ntohs(t4->u_port);
2131   }
2132   else
2133   {
2134     /* invalid address */
2135     GNUNET_break_op (0);
2136     asc (asc_cls, NULL);
2137     return;
2138   }
2139   res = GNUNET_asprintf(&ret,"%s://%s:%u/", PROTOCOL_PREFIX, address,port);
2140   GNUNET_free (address);
2141   GNUNET_assert(res != 0);
2142   asc (asc_cls, ret);
2143   GNUNET_free_non_null (ret);
2144 }
2145
2146
2147
2148 /**
2149  * Another peer has suggested an address for this
2150  * peer and transport plugin.  Check that this could be a valid
2151  * address.  If so, consider adding it to the list
2152  * of addresses.
2153  *
2154  * @param cls closure
2155  * @param addr pointer to the address
2156  * @param addrlen length of addr
2157  * @return GNUNET_OK if this is a plausible address for this peer
2158  *         and transport
2159  */
2160 static int
2161 http_plugin_address_suggested (void *cls,
2162                                const void *addr, size_t addrlen)
2163 {
2164   struct Plugin *plugin = cls;
2165   struct IPv4HttpAddress *v4;
2166   struct IPv6HttpAddress *v6;
2167   unsigned int port;
2168
2169   GNUNET_assert(cls !=NULL);
2170   if ((addrlen != sizeof (struct IPv4HttpAddress)) &&
2171       (addrlen != sizeof (struct IPv6HttpAddress)))
2172     {
2173       return GNUNET_SYSERR;
2174     }
2175   if (addrlen == sizeof (struct IPv4HttpAddress))
2176     {
2177       v4 = (struct IPv4HttpAddress *) addr;
2178       /* Not skipping loopback
2179       if (INADDR_LOOPBACK == ntohl(v4->ipv4_addr))
2180       {
2181         return GNUNET_SYSERR;
2182       } */
2183       port = ntohs (v4->u_port);
2184       if (port != plugin->port_inbound)
2185       {
2186         return GNUNET_SYSERR;
2187       }
2188     }
2189   if (addrlen == sizeof (struct IPv6HttpAddress))
2190     {
2191       v6 = (struct IPv6HttpAddress *) addr;
2192       if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2193         {
2194           return GNUNET_SYSERR;
2195         }
2196       port = ntohs (v6->u6_port);
2197       if (port != plugin->port_inbound)
2198       {
2199         return GNUNET_SYSERR;
2200       }
2201     }
2202
2203   return GNUNET_OK;
2204 }
2205
2206
2207 /**
2208  * Function called for a quick conversion of the binary address to
2209  * a numeric address.  Note that the caller must not free the
2210  * address and that the next call to this function is allowed
2211  * to override the address again.
2212  *
2213  * @param cls closure
2214  * @param addr binary address
2215  * @param addrlen length of the address
2216  * @return string representing the same address
2217  */
2218 static const char*
2219 http_plugin_address_to_string (void *cls,
2220                                    const void *addr,
2221                                    size_t addrlen)
2222 {
2223   const struct IPv4HttpAddress *t4;
2224   const struct IPv6HttpAddress *t6;
2225   struct sockaddr_in a4;
2226   struct sockaddr_in6 a6;
2227   char * address;
2228   char * ret;
2229   uint16_t port;
2230   unsigned int res;
2231
2232   if (addrlen == sizeof (struct IPv6HttpAddress))
2233     {
2234       address = GNUNET_malloc (INET6_ADDRSTRLEN);
2235       t6 = addr;
2236       a6.sin6_addr = t6->ipv6_addr;
2237       inet_ntop(AF_INET6, &(a6.sin6_addr),address,INET6_ADDRSTRLEN);
2238       port = ntohs(t6->u6_port);
2239     }
2240   else if (addrlen == sizeof (struct IPv4HttpAddress))
2241     {
2242       address = GNUNET_malloc (INET_ADDRSTRLEN);
2243       t4 = addr;
2244       a4.sin_addr.s_addr =  t4->ipv4_addr;
2245       inet_ntop(AF_INET, &(a4.sin_addr),address,INET_ADDRSTRLEN);
2246       port = ntohs(t4->u_port);
2247     }
2248   else
2249     {
2250       /* invalid address */
2251       return NULL;
2252     }
2253   res = GNUNET_asprintf(&ret,"%s:%u",address,port);
2254   GNUNET_free (address);
2255   GNUNET_assert(res != 0);
2256   return ret;
2257 }
2258
2259 static char *
2260 load_certificate( const char * file )
2261 {
2262   struct GNUNET_DISK_FileHandle * gn_file;
2263
2264   struct stat fstat;
2265   char * text = NULL;
2266
2267   if (0!=STAT(file, &fstat))
2268           return NULL;
2269   text = GNUNET_malloc (fstat.st_size);
2270   gn_file = GNUNET_DISK_file_open(file,GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_USER_READ);
2271   if (gn_file==NULL)
2272   {
2273           GNUNET_free(text);
2274           return NULL;
2275   }
2276   if (GNUNET_SYSERR == GNUNET_DISK_file_read(gn_file, text, fstat.st_size))
2277   {
2278           GNUNET_free(text);
2279           return NULL;
2280   }
2281   text[fstat.st_size] = '\0';
2282   GNUNET_DISK_file_close(gn_file);
2283
2284   return text;
2285 }
2286
2287
2288 /**
2289  * Exit point from the plugin.
2290  */
2291 void *
2292 libgnunet_plugin_transport_https_done (void *cls)
2293 {
2294   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2295   struct Plugin *plugin = api->cls;
2296   CURLMcode mret;
2297   GNUNET_assert(cls !=NULL);
2298
2299   if (plugin->http_server_daemon_v4 != NULL)
2300   {
2301     MHD_stop_daemon (plugin->http_server_daemon_v4);
2302     plugin->http_server_daemon_v4 = NULL;
2303   }
2304   if (plugin->http_server_daemon_v6 != NULL)
2305   {
2306     MHD_stop_daemon (plugin->http_server_daemon_v6);
2307     plugin->http_server_daemon_v6 = NULL;
2308   }
2309
2310   if ( plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
2311   {
2312     GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v4);
2313     plugin->http_server_task_v4 = GNUNET_SCHEDULER_NO_TASK;
2314   }
2315
2316   if ( plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
2317   {
2318     GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v6);
2319     plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
2320   }
2321
2322
2323   /* free all peer information */
2324   if (plugin->peers!=NULL)
2325   {
2326           GNUNET_CONTAINER_multihashmap_iterate (plugin->peers,
2327                                                                                          &remove_peer_context_Iterator,
2328                                                                                          plugin);
2329           GNUNET_CONTAINER_multihashmap_destroy (plugin->peers);
2330   }
2331   if (plugin->multi_handle!=NULL)
2332   {
2333           mret = curl_multi_cleanup(plugin->multi_handle);
2334 #if DEBUG_HTTPS
2335           if ( CURLM_OK != mret)
2336                 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"curl multihandle clean up failed\n");
2337 #endif
2338           plugin->multi_handle = NULL;
2339   }
2340   curl_global_cleanup();
2341
2342   if ( plugin->http_curl_task != GNUNET_SCHEDULER_NO_TASK)
2343   {
2344     GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_curl_task);
2345     plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK;
2346   }
2347
2348   GNUNET_free_non_null (plugin->bind4_address);
2349   GNUNET_free_non_null (plugin->bind6_address);
2350   GNUNET_free_non_null(plugin->bind_hostname);
2351   GNUNET_free (plugin);
2352   GNUNET_free (api);
2353 #if DEBUG_HTTPS
2354   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Unload http plugin complete...\n");
2355 #endif
2356   return NULL;
2357 }
2358
2359
2360 /**
2361  * Entry point for the plugin.
2362  */
2363 void *
2364 libgnunet_plugin_transport_https_init (void *cls)
2365 {
2366   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2367   struct Plugin *plugin;
2368   struct GNUNET_TRANSPORT_PluginFunctions *api;
2369   struct GNUNET_TIME_Relative gn_timeout;
2370   long long unsigned int port;
2371
2372   char * key_file;
2373   char * cert_file;
2374
2375   GNUNET_assert(cls !=NULL);
2376 #if DEBUG_HTTPS
2377   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting https plugin...\n");
2378 #endif
2379
2380   plugin = GNUNET_malloc (sizeof (struct Plugin));
2381   plugin->stats = env->stats;
2382   plugin->env = env;
2383   plugin->peers = NULL;
2384   plugin->bind4_address = NULL;
2385   plugin->use_ipv6  = GNUNET_YES;
2386   plugin->use_ipv4  = GNUNET_YES;
2387
2388   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
2389   api->cls = plugin;
2390   api->send = &http_plugin_send;
2391   api->disconnect = &http_plugin_disconnect;
2392   api->address_pretty_printer = &http_plugin_address_pretty_printer;
2393   api->check_address = &http_plugin_address_suggested;
2394   api->address_to_string = &http_plugin_address_to_string;
2395
2396   /* Hashing our identity to use it in URLs */
2397   GNUNET_CRYPTO_hash_to_enc ( &(plugin->env->my_identity->hashPubKey), &plugin->my_ascii_hash_ident);
2398
2399   /* Use IPv6 yes/no */
2400   if (GNUNET_CONFIGURATION_have_value (env->cfg,
2401                                                                    "transport-https", "USE_IPv6"))
2402     {
2403           plugin->use_ipv6 = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2404                                                                                                            "transport-https",
2405                                                                                                            "USE_IPv6");
2406     }
2407   /* Use IPv4 yes/no */
2408   if (GNUNET_CONFIGURATION_have_value (env->cfg,
2409                                                                    "transport-https", "USE_IPv4"))
2410     {
2411           plugin->use_ipv4 = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2412                                                                                                            "transport-https",
2413                                                                                                            "USE_IPv4");
2414     }
2415   /* Reading port number from config file */
2416   if ((GNUNET_OK !=
2417        GNUNET_CONFIGURATION_get_value_number (env->cfg,
2418                                               "transport-https",
2419                                               "PORT",
2420                                               &port)) ||
2421       (port > 65535) )
2422     {
2423       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2424                        "http",
2425                        _("Require valid port number for transport plugin `%s' in configuration!\n"),
2426                        "transport-https");
2427       libgnunet_plugin_transport_https_done (api);
2428       return NULL;
2429     }
2430
2431   /* Reading ipv4 addresse to bind to from config file */
2432   if ((plugin->use_ipv4==GNUNET_YES) && (GNUNET_CONFIGURATION_have_value (env->cfg,
2433                                                                    "transport-https", "BINDTO4")))
2434   {
2435           GNUNET_break (GNUNET_OK ==
2436                                         GNUNET_CONFIGURATION_get_value_string (env->cfg,
2437                                                                                                                    "transport-https",
2438                                                                                                                    "BINDTO4",
2439                                                                                                                    &plugin->bind_hostname));
2440           plugin->bind4_address = GNUNET_malloc(sizeof(struct sockaddr_in));
2441           plugin->bind4_address->sin_family = AF_INET;
2442           plugin->bind4_address->sin_port = htons (port);
2443
2444           if (inet_pton(AF_INET,plugin->bind_hostname, &plugin->bind4_address->sin_addr)<=0)
2445           {
2446                   GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2447                                                    "http",
2448                                                    _("Misconfigured address to bind to in configuration!\n"),
2449                                                    "transport-https");
2450                   GNUNET_free(plugin->bind4_address);
2451                   GNUNET_free(plugin->bind_hostname);
2452                   plugin->bind_hostname = NULL;
2453                   plugin->bind4_address = NULL;
2454           }
2455   }
2456
2457   /* Get private key file from config */
2458   if (GNUNET_CONFIGURATION_have_value (env->cfg,
2459                                                                            "transport-https", "KEY_FILE"))
2460   {
2461                 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2462                                                                                            "transport-https",
2463                                                                                            "KEY_FILE",
2464                                                                                            &key_file);
2465   }
2466   else
2467   {
2468           GNUNET_asprintf(&key_file,"https.key");
2469   }
2470
2471   /* Get private key file from config */
2472   if (GNUNET_CONFIGURATION_have_value (env->cfg,
2473                                                                            "transport-https", "CERT_FILE"))
2474   {
2475           GNUNET_CONFIGURATION_get_value_string (env->cfg,
2476                                                                                          "transport-https",
2477                                                                                      "CERT_FILE",
2478                                                                                      &cert_file);
2479   }
2480   else
2481   {
2482           GNUNET_asprintf(&cert_file,"https.cert");
2483   }
2484
2485   /* Reading ipv4 addresse to bind to from config file */
2486   if ((plugin->use_ipv6==GNUNET_YES) && (GNUNET_CONFIGURATION_have_value (env->cfg,
2487                                                                    "transport-https", "BINDTO6")))
2488   {
2489           GNUNET_break (GNUNET_OK ==
2490                                         GNUNET_CONFIGURATION_get_value_string (env->cfg,
2491                                                                                                                    "transport-https",
2492                                                                                                                    "BINDTO6",
2493                                                                                                                    &plugin->bind_hostname));
2494
2495           plugin->bind6_address = GNUNET_malloc(sizeof(struct sockaddr_in6));
2496           plugin->bind6_address->sin6_family = AF_INET6;
2497           plugin->bind6_address->sin6_port = htons (port);
2498
2499       if (inet_pton(AF_INET6,plugin->bind_hostname, &plugin->bind6_address->sin6_addr)<=0)
2500           {
2501                   GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2502                                                    "http",
2503                                                    _("Misconfigured address to bind to in configuration!\n"),
2504                                                    "transport-https");
2505                   GNUNET_free(plugin->bind6_address);
2506                   GNUNET_free(plugin->bind_hostname);
2507                   plugin->bind_hostname = NULL;
2508                   plugin->bind6_address = NULL;
2509           }
2510   }
2511
2512   /* read key & certificates from file */
2513   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading TLS certificate `%s' `%s'\n", key_file, cert_file);
2514
2515   plugin->key = load_certificate( key_file );
2516   plugin->cert = load_certificate( cert_file );
2517
2518   if ((plugin->key==NULL) || (plugin->cert==NULL))
2519   {
2520           char * cmd;
2521           int ret = 0;
2522           GNUNET_asprintf(&cmd,"gnunet-transport-certificate-creation %s %s", key_file, cert_file);
2523           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No usable TLS certificate found, creating certificate \n");
2524           ret = system(cmd);
2525
2526           if (ret != 0)
2527           {
2528                   GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2529                                            "https",
2530                                                    _("Could not create a new TLS certificate, shell script `%s' failed!\n"),cmd,
2531                                                    "transport-https");
2532                   GNUNET_free (key_file);
2533                   GNUNET_free (cert_file);
2534                   libgnunet_plugin_transport_https_done(api);
2535                   GNUNET_free (cmd);
2536                   return NULL;
2537           }
2538
2539           GNUNET_free (cmd);
2540
2541           plugin->key = load_certificate( key_file );
2542           plugin->cert = load_certificate( cert_file );
2543
2544           if ((plugin->key==NULL) || (plugin->cert==NULL))
2545           {
2546                   GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2547                                            "https",
2548                                                    _("No usable TLS certificate found and creating one failed! \n"),
2549                                                    "transport-https");
2550                   GNUNET_free (key_file);
2551                   GNUNET_free (cert_file);
2552                   libgnunet_plugin_transport_https_done(api);
2553                   return NULL;
2554           }
2555   }
2556
2557   GNUNET_free (key_file);
2558   GNUNET_free (cert_file);
2559
2560
2561   GNUNET_assert((plugin->key!=NULL) && (plugin->cert!=NULL));
2562   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n", key_file, cert_file);
2563
2564   GNUNET_assert ((port > 0) && (port <= 65535));
2565   plugin->port_inbound = port;
2566   gn_timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
2567   unsigned int timeout = (gn_timeout.value) / 1000;
2568   if ((plugin->http_server_daemon_v6 == NULL) && (plugin->use_ipv6 == GNUNET_YES) && (port != 0))
2569   {
2570         struct sockaddr * tmp = (struct sockaddr *) plugin->bind6_address;
2571     plugin->http_server_daemon_v6 = MHD_start_daemon (
2572 #if DEBUG_CONNECTIONS
2573                                                                    MHD_USE_DEBUG |
2574 #endif
2575                                                                    MHD_USE_IPv6 | MHD_USE_SSL,
2576                                        port,
2577                                        &mhd_accept_cb,
2578                                        plugin , &mdh_access_cb, plugin,
2579                                        MHD_OPTION_HTTPS_MEM_KEY, plugin->key,
2580                                        MHD_OPTION_HTTPS_MEM_CERT, plugin->cert,
2581                                        MHD_OPTION_SOCK_ADDR, tmp,
2582                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 32,
2583                                        //MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 6,
2584                                        MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) timeout,
2585                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
2586                                        MHD_OPTION_NOTIFY_COMPLETED, &mhd_termination_cb, NULL,
2587                                        MHD_OPTION_END);
2588   }
2589   if ((plugin->http_server_daemon_v4 == NULL) && (plugin->use_ipv4 == GNUNET_YES) && (port != 0))
2590   {
2591   plugin->http_server_daemon_v4 = MHD_start_daemon (
2592 #if DEBUG_CONNECTIONS
2593                                                                    MHD_USE_DEBUG |
2594 #endif
2595                                                                    MHD_NO_FLAG | MHD_USE_SSL,
2596                                        port,
2597                                        &mhd_accept_cb,
2598                                        plugin , &mdh_access_cb, plugin,
2599                                        MHD_OPTION_HTTPS_MEM_KEY, plugin->key,
2600                                        MHD_OPTION_HTTPS_MEM_CERT, plugin->cert,
2601                                        MHD_OPTION_SOCK_ADDR, (struct sockaddr_in *)plugin->bind4_address,
2602                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 32,
2603                                        //MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 6,
2604                                        MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) timeout,
2605                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
2606                                        MHD_OPTION_NOTIFY_COMPLETED, &mhd_termination_cb, NULL,
2607                                        MHD_OPTION_END);
2608   }
2609   if (plugin->http_server_daemon_v4 != NULL)
2610     plugin->http_server_task_v4 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v4);
2611   if (plugin->http_server_daemon_v6 != NULL)
2612     plugin->http_server_task_v6 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v6);
2613
2614
2615   if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
2616   {
2617 #if DEBUG_HTTPS
2618           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting HTTPS Server with IPv4 bound to %s with port %u\n",(plugin->bind_hostname!=NULL) ? plugin->bind_hostname : "every address",port);
2619 #endif
2620   }
2621   else if ((plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK) && (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK))
2622   {
2623 #if DEBUG_HTTPS
2624     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting HTTPS Server with IPv6 bound to %s with port %u\n",(plugin->bind_hostname!=NULL) ? plugin->bind_hostname : "every address", port);
2625 #endif
2626   }
2627   else if ((plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK) && (plugin->http_server_task_v4 == GNUNET_SCHEDULER_NO_TASK))
2628   {
2629 #if DEBUG_HTTPS
2630     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting HTTPS Server with IPv4 and IPv6 bound to %s with port %u\n",(plugin->bind_hostname!=NULL) ? plugin->bind_hostname : "every address", port);
2631 #endif
2632   }
2633   else
2634   {
2635         char * tmp;
2636         if ((plugin->use_ipv6 == GNUNET_YES) && (plugin->use_ipv4 == GNUNET_YES))
2637                 GNUNET_asprintf(&tmp,"with IPv4 and IPv6 enabled");
2638         if ((plugin->use_ipv6 == GNUNET_NO) && (plugin->use_ipv4 == GNUNET_YES))
2639                 GNUNET_asprintf(&tmp,"with IPv4 enabled");
2640         if ((plugin->use_ipv6 == GNUNET_YES) && (plugin->use_ipv4 == GNUNET_NO))
2641                 GNUNET_asprintf(&tmp,"with IPv6 enabled");
2642         if ((plugin->use_ipv6 == GNUNET_NO) && (plugin->use_ipv4 == GNUNET_NO))
2643                 GNUNET_asprintf(&tmp,"with NO IP PROTOCOL enabled");
2644         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"HTTPS Server with %s could not be started on port %u! https plugin failed!\n",tmp, port);
2645         GNUNET_free(tmp);
2646     libgnunet_plugin_transport_https_done (api);
2647     return NULL;
2648   }
2649
2650   /* Initializing cURL */
2651   curl_global_init(CURL_GLOBAL_ALL);
2652   plugin->multi_handle = curl_multi_init();
2653
2654   if ( NULL == plugin->multi_handle )
2655   {
2656     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2657                                    "http",
2658                                    _("Could not initialize curl multi handle, failed to start http plugin!\n"),
2659                                    "transport-https");
2660     libgnunet_plugin_transport_https_done (api);
2661     return NULL;
2662   }
2663
2664   plugin->peers = GNUNET_CONTAINER_multihashmap_create (10);
2665   GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
2666
2667   return api;
2668 }
2669
2670 /* end of plugin_transport_https.c */