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