src: for every AGPL3.0 file, add SPDX identifier.
[oweals/gnunet.git] / src / transport / plugin_transport_http_common.c
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2002-2013 GNUnet e.V.
4
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your 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  Affero General Public License for more details.
14
15  You should have received a copy of the GNU Affero General Public License
16  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file transport/plugin_transport_http_common.c
23  * @brief functionality shared between http(s)client plugins
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_transport_plugin.h"
29 #include "plugin_transport_http_common.h"
30 #include "gnunet_resolver_service.h"
31
32 static void
33 http_clean_splitted (struct SplittedHTTPAddress *spa)
34 {
35   if (NULL != spa)
36   {
37     GNUNET_free_non_null(spa->protocol);
38     GNUNET_free_non_null(spa->host);
39     GNUNET_free_non_null(spa->path);
40     GNUNET_free_non_null(spa);
41   }
42 }
43
44
45 struct SplittedHTTPAddress *
46 http_split_address (const char * addr)
47 {
48   struct SplittedHTTPAddress *sp;
49   char *src = GNUNET_strdup (addr);
50   char *protocol_start = NULL;
51   char *host_start = NULL;
52   char *v6_end = NULL;
53   char *port_start = NULL;
54   char *path_start = NULL;
55   protocol_start = src;
56
57   sp = GNUNET_new (struct SplittedHTTPAddress);
58   /* Address string consists of protocol://host[:port]path*/
59
60   host_start = strstr (src, "://");
61   if (NULL == host_start)
62   {
63     GNUNET_free(src);
64     GNUNET_free(sp);
65     return NULL ;
66   }
67   host_start[0] = '\0';
68   sp->protocol = GNUNET_strdup (protocol_start);
69
70   host_start += strlen ("://");
71   if (strlen (host_start) == 0)
72   {
73     GNUNET_free(src);
74     GNUNET_free(sp->protocol);
75     GNUNET_free(sp);
76     return NULL ;
77   }
78
79   /* Find path start */
80   path_start = strchr (host_start, '/');
81   if (NULL != path_start)
82   {
83     sp->path = GNUNET_strdup (path_start);
84     path_start[0] = '\0';
85   }
86   else
87     sp->path = GNUNET_strdup ("");
88
89   if (strlen (host_start) < 1)
90   {
91     GNUNET_free(src);
92     GNUNET_free(sp->protocol);
93     GNUNET_free(sp->path);
94     GNUNET_free(sp);
95     return NULL ;
96   }
97
98   if (NULL != (port_start = strrchr (host_start, ':')))
99   {
100     /* *We COULD have a port, but also an IPv6 address! */
101     if (NULL != (v6_end = strchr (host_start, ']')))
102     {
103       if (v6_end < port_start)
104       {
105         /* IPv6 address + port */
106         port_start[0] = '\0';
107         port_start++;
108         sp->port = atoi (port_start);
109         if ((0 == sp->port) || (65535 < sp->port))
110         {
111           GNUNET_free(src);
112           GNUNET_free(sp->protocol);
113           GNUNET_free(sp->path);
114           GNUNET_free(sp);
115           return NULL ;
116         }
117       }
118       else
119       {
120         /* IPv6 address + no port */
121         if (0 == strcmp (sp->protocol, "https"))
122           sp->port = HTTPS_DEFAULT_PORT;
123         else if (0 == strcmp (sp->protocol, "http"))
124           sp->port = HTTP_DEFAULT_PORT;
125       }
126     }
127     else
128     {
129       /* No IPv6 address */
130       port_start[0] = '\0';
131       port_start++;
132       sp->port = atoi (port_start);
133       if ((0 == sp->port) || (65535 < sp->port))
134       {
135         GNUNET_free(src);
136         GNUNET_free(sp->protocol);
137         GNUNET_free(sp->path);
138         GNUNET_free(sp);
139         return NULL ;
140       }
141     }
142   }
143   else
144   {
145     /* No ':' as port separator, default port for protocol */
146     if (0 == strcmp (sp->protocol, "https"))
147       sp->port = HTTPS_DEFAULT_PORT;
148     else if (0 == strcmp (sp->protocol, "http"))
149       sp->port = HTTP_DEFAULT_PORT;
150     else
151     {
152       GNUNET_break(0);
153       GNUNET_free(src);
154       GNUNET_free(sp->protocol);
155       GNUNET_free(sp->path);
156       GNUNET_free(sp);
157       return NULL ;
158     }
159   }
160   if (strlen (host_start) > 0)
161     sp->host = GNUNET_strdup (host_start);
162   else
163   {
164     GNUNET_break(0);
165     GNUNET_free(src);
166     GNUNET_free(sp->protocol);
167     GNUNET_free(sp->path);
168     GNUNET_free(sp);
169     return NULL ;
170   }
171   GNUNET_free(src);
172   return sp;
173 }
174
175 /**
176  * Closure for #append_port().
177  */
178 struct PrettyPrinterContext
179 {
180   /**
181    * DLL
182    */
183   struct PrettyPrinterContext *next;
184
185   /**
186    * DLL
187    */
188   struct PrettyPrinterContext *prev;
189
190   /**
191    * Resolver handle
192    */
193   struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
194
195   /**
196    * Function to call with the result.
197    */
198   GNUNET_TRANSPORT_AddressStringCallback asc;
199
200   /**
201    * Clsoure for @e asc.
202    */
203   void *asc_cls;
204
205   /**
206    * Timeout task
207    */
208   struct GNUNET_SCHEDULER_Task * timeout_task;
209
210   /**
211    * Splitted Address
212    */
213   struct SplittedHTTPAddress *saddr;
214
215   /**
216    * Plugin String
217    */
218   char *plugin;
219
220   /**
221    * Was conversion successful
222    */
223   int sucess;
224
225   /**
226    * Address options
227    */
228   uint32_t options;
229 };
230
231 /**
232  * Head of PPC list
233  */
234 static struct PrettyPrinterContext *dll_ppc_head;
235
236 /**
237  * Tail of PPC list
238  */
239 static struct PrettyPrinterContext *dll_ppc_tail;
240
241 /**
242  * Function called for a quick conversion of the binary address to
243  * a numeric address.  Note that the caller must not free the
244  * address and that the next call to this function is allowed
245  * to override the address again.
246  *
247  * @param plugin the name of the plugin
248  * @param saddr the splitted http address
249  * @param options address options
250  * @param dnsresult dns name to include in address
251  * @return string representing the same address or NULL on error
252  */
253 static const char *
254 http_common_plugin_dnsresult_to_address (const char *plugin,
255     const struct SplittedHTTPAddress *saddr,
256     uint32_t options,
257     const char *dnsresult)
258 {
259   static char rbuf[1024];
260   char *res;
261
262   GNUNET_asprintf (&res, "%s.%u.%s://%s:%u%s", plugin, options, saddr->protocol,
263       dnsresult, saddr->port, saddr->path);
264   if (strlen (res) + 1 < 500)
265   {
266     GNUNET_memcpy (rbuf, res, strlen (res) + 1);
267     GNUNET_free(res);
268     return rbuf;
269   }
270   GNUNET_break(0);
271   GNUNET_free(res);
272   return NULL ;
273 }
274
275
276 static void
277 http_common_dns_reverse_lookup_cb (void *cls, const char *hostname)
278 {
279   struct PrettyPrinterContext *ppc = cls;
280
281   if (NULL != hostname)
282   {
283     ppc->asc (ppc->asc_cls,
284         http_common_plugin_dnsresult_to_address (ppc->plugin, ppc->saddr, ppc->options,
285             hostname), GNUNET_OK);
286     ppc->sucess = GNUNET_YES;
287
288   }
289   else
290   {
291     ppc->asc (ppc->asc_cls, NULL,
292         (GNUNET_NO == ppc->sucess) ? GNUNET_SYSERR : GNUNET_OK);
293
294     GNUNET_CONTAINER_DLL_remove(dll_ppc_head, dll_ppc_tail, ppc);
295     http_clean_splitted (ppc->saddr);
296     GNUNET_free(ppc->plugin);
297     GNUNET_free(ppc);
298   }
299 }
300
301
302 static int
303 http_common_dns_reverse_lookup (const struct sockaddr *sockaddr,
304                                 socklen_t sockaddr_len,
305                                 const char *type,
306                                 struct SplittedHTTPAddress *saddr,
307                                 uint32_t options,
308                                 struct GNUNET_TIME_Relative timeout,
309                                 GNUNET_TRANSPORT_AddressStringCallback asc,
310                                 void *asc_cls)
311 {
312   struct PrettyPrinterContext *ppc;
313
314   ppc = GNUNET_new (struct PrettyPrinterContext);
315   ppc->saddr = saddr;
316   ppc->asc = asc;
317   ppc->asc_cls = asc_cls;
318   ppc->plugin = GNUNET_strdup (type);
319   ppc->options = options;
320   ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sockaddr,
321                                                        sockaddr_len,
322                                                        GNUNET_YES,
323                                                        timeout,
324                                                        &http_common_dns_reverse_lookup_cb,
325                                                        ppc);
326   if (NULL == ppc->resolver_handle)
327   {
328     GNUNET_free(ppc->plugin);
329     GNUNET_free(ppc);
330     return GNUNET_SYSERR;
331   }
332   GNUNET_CONTAINER_DLL_insert (dll_ppc_head,
333                                dll_ppc_tail,
334                                ppc);
335   return GNUNET_OK;
336 }
337
338
339 static void
340 http_common_dns_ip_lookup_cb (void *cls,
341                               const struct sockaddr *addr,
342                               socklen_t addrlen)
343 {
344   struct PrettyPrinterContext *ppc = cls;
345
346   if (NULL != addr)
347   {
348     ppc->asc (ppc->asc_cls,
349         http_common_plugin_dnsresult_to_address (ppc->plugin, ppc->saddr, ppc->options,
350             GNUNET_a2s (addr, addrlen)), GNUNET_OK);
351     ppc->sucess = GNUNET_YES;
352     ppc->asc (ppc->asc_cls, GNUNET_a2s (addr, addrlen), GNUNET_OK);
353   }
354   else
355   {
356     ppc->asc (ppc->asc_cls, NULL,
357         (GNUNET_NO == ppc->sucess) ? GNUNET_SYSERR : GNUNET_OK);
358
359     GNUNET_CONTAINER_DLL_remove(dll_ppc_head, dll_ppc_tail, ppc);
360     GNUNET_free(ppc->plugin);
361     http_clean_splitted (ppc->saddr);
362     GNUNET_free(ppc);
363   }
364 }
365
366
367 static int
368 http_common_dns_ip_lookup (const char *name,
369                            const char *type,
370                            struct SplittedHTTPAddress *saddr,
371                            uint32_t options,
372                            struct GNUNET_TIME_Relative timeout,
373                            GNUNET_TRANSPORT_AddressStringCallback asc, void *asc_cls)
374 {
375   struct PrettyPrinterContext *ppc;
376
377   ppc = GNUNET_new (struct PrettyPrinterContext);
378   ppc->sucess = GNUNET_NO;
379   ppc->saddr = saddr;
380   ppc->asc = asc;
381   ppc->asc_cls = asc_cls;
382   ppc->plugin = GNUNET_strdup (type);
383   ppc->options = options;
384   ppc->resolver_handle = GNUNET_RESOLVER_ip_get (name,
385                                                  AF_UNSPEC,
386                                                  timeout,
387                                                  &http_common_dns_ip_lookup_cb,
388                                                  ppc);
389   if (NULL == ppc->resolver_handle)
390   {
391     GNUNET_free(ppc->plugin);
392     GNUNET_free(ppc);
393     return GNUNET_SYSERR;
394   }
395   GNUNET_CONTAINER_DLL_insert (dll_ppc_head,
396                                dll_ppc_tail,
397                                ppc);
398   return GNUNET_OK;
399 }
400
401
402 /**
403  * Convert the transports address to a nice, human-readable
404  * format.
405  *
406  * @param cls closure
407  * @param type name of the transport that generated the address
408  * @param addr one of the addresses of the host, NULL for the last address
409  *        the specific address format depends on the transport
410  * @param addrlen length of the @a addr
411  * @param numeric should (IP) addresses be displayed in numeric form?
412  * @param timeout after how long should we give up?
413  * @param asc function to call on each string
414  * @param asc_cls closure for @a asc
415  */
416 void
417 http_common_plugin_address_pretty_printer (void *cls, const char *type,
418                                            const void *addr,
419                                            size_t addrlen,
420                                            int numeric,
421                                            struct GNUNET_TIME_Relative timeout,
422                                            GNUNET_TRANSPORT_AddressStringCallback asc,
423                                            void *asc_cls)
424 {
425   const struct HttpAddress *address = addr;
426   struct SplittedHTTPAddress *saddr;
427   struct sockaddr *sock_addr;
428   const char *ret;
429   char *addr_str;
430   int res;
431   int have_ip;
432
433   saddr = NULL;
434   sock_addr = NULL;
435   if ( (addrlen < sizeof(struct HttpAddress)) ||
436        (addrlen != http_common_address_get_size (address)) )
437   {
438     GNUNET_break(0);
439     goto handle_error;
440   }
441
442   addr_str = (char *) &address[1];
443   if (addr_str[ntohl (address->urlen) - 1] != '\0')
444   {
445     GNUNET_break(0);
446     goto handle_error;
447   }
448
449   saddr = http_split_address (addr_str);
450   if (NULL == saddr)
451   {
452     GNUNET_break(0);
453     goto handle_error;
454   }
455
456   sock_addr = http_common_socket_from_address (addr, addrlen, &res);
457   if (GNUNET_SYSERR == res)
458   {
459     /* Malformed address */
460     GNUNET_break (0);
461     goto handle_error;
462   }
463   else if (GNUNET_NO == res)
464   {
465     /* Could not convert to IP */
466     have_ip = GNUNET_NO;
467   }
468   else if (GNUNET_YES == res)
469   {
470     /* Converted to IP */
471     have_ip = GNUNET_YES;
472   }
473   else
474   {
475     /* Must not happen */
476     GNUNET_break (0);
477     goto handle_error;
478   }
479
480   if ( (GNUNET_YES == numeric) &&
481        (GNUNET_YES == have_ip) )
482   {
483     /* No lookup required */
484     ret = http_common_plugin_address_to_string (type, address, addrlen);
485     asc (asc_cls, ret, (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
486     asc (asc_cls, NULL, GNUNET_OK);
487     http_clean_splitted (saddr);
488     GNUNET_free_non_null (sock_addr);
489     return;
490   }
491   if ( (GNUNET_YES == numeric) &&
492        (GNUNET_NO == have_ip) )
493   {
494     /* Forward lookup */
495     if (GNUNET_SYSERR ==
496         http_common_dns_ip_lookup (saddr->host, type, saddr,
497                                    address->options, timeout,
498                                    asc, asc_cls))
499     {
500       GNUNET_break(0);
501       goto handle_error;
502     }
503     /* Wait for resolver callback */
504     GNUNET_free_non_null (sock_addr);
505     return;
506   }
507   if ( (GNUNET_NO == numeric) &&
508        (GNUNET_YES == have_ip) )
509   {
510     /* Reverse lookup */
511     if (GNUNET_SYSERR ==
512         http_common_dns_reverse_lookup (sock_addr,
513                                         (AF_INET == sock_addr->sa_family)
514                                         ? sizeof(struct sockaddr_in)
515                                         : sizeof(struct sockaddr_in6),
516                                         type,
517                                         saddr,
518                                         address->options, timeout,
519                                         asc, asc_cls))
520     {
521       GNUNET_break(0);
522       goto handle_error;
523     }
524     /* Wait for resolver callback */
525     GNUNET_free_non_null (sock_addr);
526     return;
527   }
528   if ( (GNUNET_NO == numeric) &&
529        (GNUNET_NO == have_ip) )
530   {
531     /* No lookup required */
532     ret = http_common_plugin_address_to_string (type, address, addrlen);
533     asc (asc_cls, ret, (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
534     asc (asc_cls, NULL, GNUNET_OK);
535     GNUNET_free_non_null (sock_addr);
536     http_clean_splitted (saddr);
537     return;
538   }
539   /* Error (argument supplied not GNUNET_YES or GNUNET_NO) */
540   GNUNET_break (0);
541   goto handle_error;
542
543  handle_error:
544   /* Report error */
545   asc (asc_cls, NULL, GNUNET_SYSERR);
546   asc (asc_cls, NULL, GNUNET_OK);
547   GNUNET_free_non_null (sock_addr);
548   if (NULL != saddr)
549     http_clean_splitted (saddr);
550 }
551
552
553 /**
554  * FIXME.
555  */
556 const char *
557 http_common_plugin_address_to_url (void *cls,
558                                    const void *addr,
559                                    size_t addrlen)
560 {
561   static char rbuf[1024];
562   const struct HttpAddress *address = addr;
563   const char * addr_str;
564
565   if (NULL == addr)
566   {
567     GNUNET_break(0);
568     return NULL;
569   }
570   if (0 == addrlen)
571   {
572     GNUNET_break(0);
573     return NULL;
574   }
575   if (addrlen != http_common_address_get_size (address))
576   {
577     GNUNET_break(0);
578     return NULL;
579   }
580   addr_str = (char *) &address[1];
581   if (addr_str[ntohl (address->urlen) - 1] != '\0')
582     return NULL;
583
584   GNUNET_memcpy (rbuf,
585           &address[1],
586           ntohl (address->urlen));
587   return rbuf;
588 }
589
590
591 /**
592  * Function called for a quick conversion of the binary address to
593  * a numeric address.  Note that the caller must not free the
594  * address and that the next call to this function is allowed
595  * to override the address again.
596  *
597  * @param plugin the name of the plugin
598  * @param addr binary address
599  * @param addrlen length of the address
600  * @return string representing the same address
601  */
602 const char *
603 http_common_plugin_address_to_string (const char *plugin,
604                                       const void *addr,
605                                       size_t addrlen)
606 {
607   static char rbuf[1024];
608   const struct HttpAddress *address = addr;
609   const char * addr_str;
610   char *res;
611
612   GNUNET_assert(NULL != plugin);
613   if (NULL == addr)
614     return NULL;
615   if (0 == addrlen)
616     return NULL;
617   if (addrlen != http_common_address_get_size (address))
618     return NULL;
619   addr_str = (char *) &address[1];
620   if (addr_str[ntohl (address->urlen) - 1] != '\0')
621     return NULL;
622   GNUNET_asprintf (&res, "%s.%u.%s", plugin, ntohl (address->options),
623       &address[1]);
624   if (strlen (res) + 1 < 500)
625   {
626     GNUNET_memcpy (rbuf, res, strlen (res) + 1);
627     GNUNET_free(res);
628     return rbuf;
629   }
630   GNUNET_break(0);
631   GNUNET_free(res);
632   return NULL;
633 }
634
635 /**
636  * Function called to convert a string address to
637  * a binary address.
638  *
639  * @param cls closure ('struct Plugin*')
640  * @param addr string address
641  * @param addrlen length of the @a addr
642  * @param buf location to store the buffer
643  *        If the function returns #GNUNET_SYSERR, its contents are undefined.
644  * @param added length of created address
645  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
646  */
647 int
648 http_common_plugin_string_to_address (void *cls,
649                                       const char *addr,
650                                       uint16_t addrlen,
651                                       void **buf,
652                                       size_t *added)
653 {
654   struct HttpAddress *a;
655   char *address;
656   char *plugin;
657   char *optionstr;
658   size_t urlen;
659   uint32_t options;
660
661   /* Format protocol.options.address:port */
662   address = NULL;
663   plugin = NULL;
664   optionstr = NULL;
665   if ((NULL == addr) || (addrlen == 0))
666   {
667     GNUNET_break(0);
668     return GNUNET_SYSERR;
669   }
670   if ('\0' != addr[addrlen - 1])
671   {
672     GNUNET_break(0);
673     return GNUNET_SYSERR;
674   }
675   if (strlen (addr) != addrlen - 1)
676   {
677     GNUNET_break(0);
678     return GNUNET_SYSERR;
679   }
680   plugin = GNUNET_strdup (addr);
681   optionstr = strchr (plugin, '.');
682   if (NULL == optionstr)
683   {
684     GNUNET_break(0);
685     GNUNET_free(plugin);
686     return GNUNET_SYSERR;
687   }
688   optionstr[0] = '\0';
689   optionstr++;
690   options = atol (optionstr); /* 0 on conversion error, that's ok */
691   address = strchr (optionstr, '.');
692   if (NULL == address)
693   {
694     GNUNET_break(0);
695     GNUNET_free(plugin);
696     return GNUNET_SYSERR;
697   }
698   address[0] = '\0';
699   address++;
700   urlen = strlen (address) + 1;
701
702   a = GNUNET_malloc (sizeof (struct HttpAddress) + urlen);
703   a->options = htonl (options);
704   a->urlen = htonl (urlen);
705   GNUNET_memcpy (&a[1], address, urlen);
706
707   (*buf) = a;
708   (*added) = sizeof(struct HttpAddress) + urlen;
709   GNUNET_free(plugin);
710   return GNUNET_OK;
711 }
712
713
714 /**
715  * Create a HTTP address from a socketaddr
716  *
717  * @param protocol protocol
718  * @param addr sockaddr * address
719  * @param addrlen length of the address
720  * @return the HttpAddress
721  */
722 struct HttpAddress *
723 http_common_address_from_socket (const char *protocol,
724                                  const struct sockaddr *addr,
725                                  socklen_t addrlen)
726 {
727   struct HttpAddress *address = NULL;
728   char *res;
729   size_t len;
730
731   GNUNET_asprintf (&res,
732                    "%s://%s",
733                    protocol,
734                    GNUNET_a2s (addr,
735                                addrlen));
736   len = strlen (res) + 1;
737   address = GNUNET_malloc (sizeof (struct HttpAddress) + len);
738   address->options = htonl (HTTP_OPTIONS_NONE);
739   address->urlen = htonl (len);
740   GNUNET_memcpy (&address[1], res, len);
741   GNUNET_free(res);
742   return address;
743 }
744
745
746 /**
747  * Create a socketaddr from a HTTP address
748  *
749  * @param addr a `sockaddr *` address
750  * @param addrlen length of the @a addr
751  * @param res the result:
752  *   #GNUNET_SYSERR, invalid input,
753  *   #GNUNET_YES: could convert to ip,
754  *   #GNUNET_NO: valid input but could not convert to ip (hostname?)
755  * @return the string
756  */
757 struct sockaddr *
758 http_common_socket_from_address (const void *addr,
759                                  size_t addrlen,
760                                  int *res)
761 {
762   const struct HttpAddress *ha;
763   struct SplittedHTTPAddress * spa;
764   struct sockaddr_storage *s;
765   char * to_conv;
766   size_t urlen;
767
768   (*res) = GNUNET_SYSERR;
769   ha = (const struct HttpAddress *) addr;
770   if (NULL == addr)
771   {
772     GNUNET_break (0);
773     return NULL;
774   }
775   if (0 == addrlen)
776   {
777     GNUNET_break (0);
778     return NULL;
779   }
780   if (addrlen < sizeof(struct HttpAddress))
781   {
782     GNUNET_break (0);
783     return NULL;
784   }
785   urlen = ntohl (ha->urlen);
786   if (sizeof(struct HttpAddress) + urlen != addrlen)
787   {
788     /* This is a legacy addresses */
789     return NULL;
790   }
791   if (addrlen < sizeof(struct HttpAddress) + urlen)
792   {
793     /* This is a legacy addresses */
794     return NULL;
795   }
796   if (((char *) addr)[addrlen - 1] != '\0')
797   {
798     GNUNET_break (0);
799     return NULL;
800   }
801   spa = http_split_address ((const char *) &ha[1]);
802   if (NULL == spa)
803   {
804     (*res) = GNUNET_SYSERR;
805     return NULL;
806   }
807
808   s = GNUNET_new (struct sockaddr_storage);
809   GNUNET_asprintf (&to_conv, "%s:%u", spa->host, spa->port);
810   if (GNUNET_SYSERR
811       == GNUNET_STRINGS_to_address_ip (to_conv, strlen (to_conv), s))
812   {
813     /* could be a hostname */
814     GNUNET_free(s);
815     (*res) = GNUNET_NO;
816     s = NULL;
817   }
818   else if ((AF_INET != s->ss_family) && (AF_INET6 != s->ss_family))
819   {
820     GNUNET_free (s);
821     (*res) = GNUNET_SYSERR;
822     s = NULL;
823   }
824   else
825   {
826     (*res) = GNUNET_YES;
827   }
828   http_clean_splitted (spa);
829   GNUNET_free (to_conv);
830   return (struct sockaddr *) s;
831 }
832
833
834 /**
835  * Get the length of an address
836  *
837  * @param addr address
838  * @return the size
839  */
840 size_t
841 http_common_address_get_size (const struct HttpAddress * addr)
842 {
843   return sizeof(struct HttpAddress) + ntohl (addr->urlen);
844 }
845
846
847 /**
848  * Compare addr1 to addr2
849  *
850  * @param addr1 address1
851  * @param addrlen1 address 1 length
852  * @param addr2 address2
853  * @param addrlen2 address 2 length
854  * @return #GNUNET_YES if equal, #GNUNET_NO if not, #GNUNET_SYSERR on error
855  */
856 size_t
857 http_common_cmp_addresses (const void *addr1,
858                            size_t addrlen1,
859                            const void *addr2,
860                            size_t addrlen2)
861 {
862   const char *a1 = addr1;
863   const char *a2 = addr2;
864   const struct HttpAddress *ha1;
865   const struct HttpAddress *ha2;
866   ha1 = (const struct HttpAddress *) a1;
867   ha2 = (const struct HttpAddress *) a2;
868
869   if (NULL == a1)
870     return GNUNET_SYSERR;
871   if (0 == addrlen1)
872     return GNUNET_SYSERR;
873   if (a1[addrlen1 - 1] != '\0')
874     return GNUNET_SYSERR;
875
876   if (NULL == a2)
877     return GNUNET_SYSERR;
878   if (0 == addrlen2)
879     return GNUNET_SYSERR;
880   if (a2[addrlen2 - 1] != '\0')
881     return GNUNET_SYSERR;
882
883   if (addrlen1 != addrlen2)
884     return GNUNET_NO;
885   if (ha1->urlen != ha2->urlen)
886     return GNUNET_NO;
887
888   if (0 == strcmp ((const char *) &ha1[1], (const char *) &ha2[1]))
889     return GNUNET_YES;
890   return GNUNET_NO;
891 }
892
893
894 /**
895  * Function obtain the network type for an address.
896  *
897  * @param env the environment
898  * @param address the address
899  * @return the network type
900  */
901 enum GNUNET_NetworkType
902 http_common_get_network_for_address (struct GNUNET_TRANSPORT_PluginEnvironment *env,
903                                      const struct GNUNET_HELLO_Address *address)
904 {
905
906   struct sockaddr *sa;
907   enum GNUNET_NetworkType net_type;
908   size_t salen = 0;
909   int res;
910
911   net_type = GNUNET_NT_UNSPECIFIED;
912   sa = http_common_socket_from_address (address->address,
913                                         address->address_length,
914                                         &res);
915   if (GNUNET_SYSERR == res)
916     return net_type;
917   if (GNUNET_YES == res)
918   {
919     GNUNET_assert (NULL != sa);
920     if (AF_INET == sa->sa_family)
921     {
922       salen = sizeof (struct sockaddr_in);
923     }
924     else if (AF_INET6 == sa->sa_family)
925     {
926       salen = sizeof (struct sockaddr_in6);
927     }
928     net_type = env->get_address_type (env->cls,
929                                       sa,
930                                       salen);
931     GNUNET_free (sa);
932   }
933   return net_type;
934 }
935
936
937
938 /* end of plugin_transport_http_common.c */