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