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