Extending the testcases to use bluetooth
[oweals/gnunet.git] / src / transport / plugin_transport_http_common.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_http_common.c
23  * @brief functionality shared by http client and server transport service plugin
24  * @author Matthias Wachs
25  */
26
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_transport_plugin.h"
30 #include "plugin_transport_http_common.h"
31
32 struct SplittedHTTPAddress
33 {
34         char *protocol;
35         char *host;
36         char *path;
37         int port;
38 };
39
40 static void
41 http_clean_splitted (struct SplittedHTTPAddress *spa)
42 {
43         if (NULL != spa)
44         {
45                         GNUNET_free_non_null (spa->protocol);
46                         GNUNET_free_non_null (spa->host);
47                         GNUNET_free_non_null (spa->path);
48                         GNUNET_free_non_null (spa);
49         }
50 }
51
52 struct SplittedHTTPAddress *
53 http_split_address (const char * addr)
54 {
55         struct SplittedHTTPAddress  *sp;
56         char *src = GNUNET_strdup (addr);
57         char *protocol_start = NULL;
58         char *host_start = NULL;
59         char *v6_end = NULL;
60         char *port_start = NULL;
61         char *path_start = NULL;
62         protocol_start = src;
63         sp = GNUNET_malloc (sizeof (struct SplittedHTTPAddress));
64
65         /* Address string consists of protocol://host[:port]path*/
66
67         host_start = strstr (src, "://");
68         if (NULL == host_start)
69         {
70                         GNUNET_free (src);
71                         GNUNET_free (sp);
72                         return NULL;
73         }
74
75         host_start[0] = '\0';
76         sp->protocol = GNUNET_strdup (protocol_start);
77
78         host_start += strlen ("://");
79         if (strlen (host_start) == 0)
80         {
81                         GNUNET_free (src);
82                         GNUNET_free (sp->protocol);
83                         GNUNET_free (sp);
84                         return NULL;
85         }
86
87         /* Find path start */
88         path_start = strchr (host_start, '/');
89         if (NULL != path_start)
90         {
91                         sp->path = GNUNET_strdup (path_start);
92                         path_start[0] = '\0';
93         }
94         else
95                 sp->path = GNUNET_strdup ("");
96
97         if (strlen(host_start) < 1)
98         {
99                         GNUNET_free (src);
100                         GNUNET_free (sp->protocol);
101                         GNUNET_free (sp->path);
102                         GNUNET_free (sp);
103                         return NULL;
104         }
105
106         if (NULL != (port_start = strrchr (host_start, ':')))
107         {
108                         /* *We COULD have a port, but also an IPv6 address! */
109                         if (NULL != (v6_end = strchr(host_start, ']')))
110                         {
111                                         if  (v6_end < port_start)
112                                         {
113                                                         /* IPv6 address + port */
114                                                         port_start[0] = '\0';
115                                                         port_start ++;
116                                                         sp->port = atoi (port_start);
117                                                         if ((0 == sp->port) || (65535 < sp->port))
118                                                         {
119                                                                 GNUNET_free (src);
120                                                                 GNUNET_free (sp->protocol);
121                                                                 GNUNET_free (sp->path);
122                                                                 GNUNET_free (sp);
123                                                                 return NULL;
124                                                         }
125                                         }
126                                         else
127                                         {
128                                                         /* IPv6 address + no port */
129                                                         if (0 == strcmp(sp->protocol, "https"))
130                                                                 sp->port = HTTPS_DEFAULT_PORT;
131                                                         else if (0 == strcmp(sp->protocol, "http"))
132                                                                 sp->port = HTTP_DEFAULT_PORT;
133                                         }
134                         }
135                         else
136                         {
137                                         /* No IPv6 address */
138                                         port_start[0] = '\0';
139                                         port_start ++;
140                                         sp->port = atoi (port_start);
141                                         if ((0 == sp->port) || (65535 < sp->port))
142                                         {
143                                                 GNUNET_free (src);
144                                                 GNUNET_free (sp->protocol);
145                                                 GNUNET_free (sp->path);
146                                                 GNUNET_free (sp);
147                                                 return NULL;
148                                         }
149                         }
150         }
151         else
152         {
153                 /* No ':' as port separator, default port for protocol */
154                 if (0 == strcmp(sp->protocol, "https"))
155                         sp->port = HTTPS_DEFAULT_PORT;
156                 else if (0 == strcmp(sp->protocol, "http"))
157                         sp->port = HTTP_DEFAULT_PORT;
158                 else
159                 {
160                                 GNUNET_break (0);
161                                 GNUNET_free (src);
162                                 GNUNET_free (sp->protocol);
163                                 GNUNET_free (sp->path);
164                                 GNUNET_free (sp);
165                                 return NULL;
166                 }
167         }
168         if (strlen (host_start) > 0)
169                         sp->host = GNUNET_strdup (host_start);
170         else
171         {
172                         GNUNET_break (0);
173                         GNUNET_free (src);
174                         GNUNET_free (sp->protocol);
175                         GNUNET_free (sp->path);
176                         GNUNET_free (sp);
177                         return NULL;
178         }
179         GNUNET_free (src);
180         return sp;
181 }
182
183 /**
184  * Convert the transports address to a nice, human-readable
185  * format.
186  *
187  * @param cls closure
188  * @param type name of the transport that generated the address
189  * @param addr one of the addresses of the host, NULL for the last address
190  *        the specific address format depends on the transport
191  * @param addrlen length of the address
192  * @param numeric should (IP) addresses be displayed in numeric form?
193  * @param timeout after how long should we give up?
194  * @param asc function to call on each string
195  * @param asc_cls closure for asc
196  */
197 void
198 http_common_plugin_address_pretty_printer (void *cls, const char *type,
199                                         const void *addr, size_t addrlen,
200                                         int numeric,
201                                         struct GNUNET_TIME_Relative timeout,
202                                         GNUNET_TRANSPORT_AddressStringCallback
203                                         asc, void *asc_cls)
204 {
205         const struct HttpAddress *address = addr;
206
207   if (NULL == http_common_plugin_address_to_string (NULL, (char *) type, address, addrlen))
208   {
209       asc (asc_cls, NULL);
210       return;
211   }
212   asc (asc_cls, http_common_plugin_address_to_string (NULL, (char *) type, address, addrlen));
213   asc (asc_cls, NULL);
214 }
215
216 const char *
217 http_common_plugin_address_to_url (void *cls, const void *addr, size_t addrlen)
218 {
219   static char rbuf[1024];
220         const struct HttpAddress *address = addr;
221   const char * addr_str;
222
223
224
225   if (NULL == addr)
226   {
227         GNUNET_break (0);
228     return NULL;
229   }
230   if (0 >= addrlen)
231   {
232         GNUNET_break (0);
233     return NULL;
234   }
235   if (addrlen != http_common_address_get_size (address))
236   {
237         GNUNET_break (0);
238     return NULL;
239   }
240   addr_str = (char *) &address[1];
241
242   if (addr_str[ntohl(address->urlen) -1] != '\0')
243     return NULL;
244
245   memcpy (rbuf, &address[1], ntohl(address->urlen));
246   return rbuf;
247 }
248
249 /**
250  * Function called for a quick conversion of the binary address to
251  * a numeric address.  Note that the caller must not free the
252  * address and that the next call to this function is allowed
253  * to override the address again.
254  *
255  * @param cls closure
256  * @param plugin the plugin
257  * @param addr binary address
258  * @param addrlen length of the address
259  * @return string representing the same address
260  */
261 const char *
262 http_common_plugin_address_to_string (void *cls, char *plugin, const void *addr, size_t addrlen)
263 {
264   static char rbuf[1024];
265         const struct HttpAddress *address = addr;
266   const char * addr_str;
267   char *res;
268
269   GNUNET_assert (NULL != plugin);
270
271   if (NULL == addr)
272       return NULL;
273   if (0 == addrlen)
274     return TRANSPORT_SESSION_INBOUND_STRING;
275   if (addrlen != http_common_address_get_size (address))
276         return NULL;
277   addr_str = (char *) &address[1];
278
279   if (addr_str[ntohl(address->urlen) -1] != '\0')
280     return NULL;
281   GNUNET_asprintf (&res, "%s.%u.%s", plugin, ntohl(address->options), &address[1]);
282   if (strlen(res) + 1 < 500)
283   {
284         memcpy (rbuf, res, strlen(res) + 1);
285         GNUNET_free (res);
286         return rbuf;
287   }
288   GNUNET_break (0);
289         GNUNET_free (res);
290         return NULL;
291 }
292
293 /**
294  * Function called to convert a string address to
295  * a binary address.
296  *
297  * @param cls closure ('struct Plugin*')
298  * @param addr string address
299  * @param addrlen length of the address
300  * @param buf location to store the buffer
301  *        If the function returns GNUNET_SYSERR, its contents are undefined.
302  * @param added length of created address
303  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
304  */
305 int
306 http_common_plugin_string_to_address (void *cls,
307                         const char *addr,
308                         uint16_t addrlen,
309                         void **buf,
310                         size_t *added)
311 {
312         struct HttpAddress *a;
313   char *address;
314   char *plugin;
315   char *optionstr;
316   size_t urlen;
317   uint32_t options;
318
319   /* Format protocol.options.address:port */
320   address = NULL;
321   plugin = NULL;
322   optionstr = NULL;
323   options = 0;
324   if ((NULL == addr) || (addrlen == 0))
325   {
326     GNUNET_break (0);
327     return GNUNET_SYSERR;
328   }
329   if ('\0' != addr[addrlen - 1])
330   {
331     GNUNET_break (0);
332     return GNUNET_SYSERR;
333   }
334   if (strlen (addr) != addrlen - 1)
335   {
336     GNUNET_break (0);
337     return GNUNET_SYSERR;
338   }
339   plugin = GNUNET_strdup (addr);
340   optionstr = strchr (plugin, '.');
341   if (NULL == optionstr)
342   {
343     GNUNET_break (0);
344     GNUNET_free (plugin);
345     return GNUNET_SYSERR;
346   }
347   optionstr[0] = '\0';
348   optionstr ++;
349   options = atol (optionstr);
350   address = strchr (optionstr, '.');
351   if (NULL == address)
352   {
353     GNUNET_break (0);
354     GNUNET_free (plugin);
355     return GNUNET_SYSERR;
356   }
357   address[0] = '\0';
358   address ++;
359   urlen = strlen (address) + 1;
360
361   a = GNUNET_malloc (sizeof (struct HttpAddress) + urlen);
362   a->options = htonl(options);
363   a->urlen = htonl(urlen);
364   memcpy (&a[1], address, urlen);
365
366   (*buf) = a;
367   (*added) = sizeof (struct HttpAddress) + urlen;
368   GNUNET_free (plugin);
369   return GNUNET_OK;
370 }
371
372 /**
373  * Create a HTTP address from a socketaddr
374  *
375  * @param protocol protocol
376  * @param addr sockaddr * address
377  * @param addrlen length of the address
378  * @return the HttpAddress
379  */
380 struct HttpAddress *
381 http_common_address_from_socket (const char *protocol, const struct sockaddr *addr, socklen_t addrlen)
382 {
383   struct HttpAddress *address = NULL;
384   char *res;
385   size_t len;
386
387   GNUNET_asprintf(&res, "%s://%s", protocol, GNUNET_a2s (addr, addrlen));
388   len = strlen (res)+1;
389
390   address = GNUNET_malloc (sizeof (struct HttpAddress) + len);
391   address->options = htonl (HTTP_OPTIONS_NONE);
392   address->urlen = htonl (len);
393   memcpy (&address[1], res, len);
394   GNUNET_free (res);
395
396   return address;
397 }
398
399 /**
400  * Create a socketaddr from a HTTP address
401  *
402  * @param addr sockaddr * address
403  * @param addrlen length of the address
404  * @param res the result:
405  * GNUNET_SYSERR, invalid input,
406  * GNUNET_YES: could convert to ip,
407  * GNUNET_NO: valid input but could not convert to ip (hostname?)
408  * @return the string
409  */
410 struct sockaddr *
411 http_common_socket_from_address (const void *addr, size_t addrlen, int *res)
412 {
413         const struct HttpAddress *ha;
414         struct SplittedHTTPAddress * spa;
415   struct sockaddr_storage *s;
416   (*res) = GNUNET_SYSERR;
417   char * to_conv;
418
419   ha = (const struct HttpAddress *) addr;
420   if (NULL == addr)
421         {
422                 GNUNET_break (0);
423                 return NULL;
424         }
425   if (0 >= addrlen)
426         {
427                 GNUNET_break (0);
428                 return NULL;
429         }
430   if (addrlen < sizeof (struct HttpAddress))
431         {
432                 GNUNET_break (0);
433                 return NULL;
434         }
435   if (addrlen < sizeof (struct HttpAddress) + ntohl (ha->urlen))
436         {
437                 /* This is a legacy addresses */
438                 return NULL;
439         }
440   if (((char *) addr)[addrlen-1] != '\0')
441         {
442                 GNUNET_break (0);
443                 return NULL;
444         }
445   spa = http_split_address ((const char *) &ha[1]);
446   if (NULL == spa)
447   {
448       (*res) = GNUNET_SYSERR;
449       return NULL;
450   }
451
452   s = GNUNET_malloc (sizeof (struct sockaddr_storage));
453   GNUNET_asprintf (&to_conv, "%s:%u", spa->host, spa->port);
454   if (GNUNET_SYSERR == GNUNET_STRINGS_to_address_ip (to_conv, strlen(to_conv), s))
455   {
456     /* could be a hostname */
457         GNUNET_free (s);
458     (*res) = GNUNET_NO;
459     s = NULL;
460   }
461   else if ((AF_INET != s->ss_family) && (AF_INET6 != s->ss_family))
462   {
463
464                 GNUNET_free (s);
465                 (*res) = GNUNET_SYSERR;
466                 s = NULL;
467   }
468   else
469   {
470                 (*res) = GNUNET_YES;
471   }
472         http_clean_splitted (spa);
473   GNUNET_free (to_conv);
474   return (struct sockaddr *) s;
475 }
476
477 /**
478  * Get the length of an address
479  *
480  * @param addr address
481  * @return the size
482  */
483 size_t
484 http_common_address_get_size (const struct HttpAddress * addr)
485 {
486  return sizeof (struct HttpAddress) + ntohl(addr->urlen);
487 }
488
489 /**
490  * Compare addr1 to addr2
491  *
492  * @param addr1 address1
493  * @param addrlen1 address 1 length
494  * @param addr2 address2
495  * @param addrlen2 address 2 length
496  * @return GNUNET_YES if equal, GNUNET_NO if not, GNUNET_SYSERR on error
497  */
498 size_t
499 http_common_cmp_addresses (const void *addr1, size_t addrlen1, const void *addr2, size_t addrlen2)
500 {
501         const struct HttpAddress *ha1;
502         const struct HttpAddress *ha2;
503   const char *a1 = (const char *) addr1;
504   const char *a2 = (const char *) addr2;
505   ha1 = (const struct HttpAddress *) a1;
506   ha2 = (const struct HttpAddress *) a2;
507
508   if (NULL == a1)
509       return GNUNET_SYSERR;
510   if (0 >= addrlen1)
511     return GNUNET_SYSERR;
512   if (a1[addrlen1-1] != '\0')
513     return GNUNET_SYSERR;
514
515   if (NULL == a2)
516       return GNUNET_SYSERR;
517   if (0 >= addrlen2)
518     return GNUNET_SYSERR;
519   if (a2[addrlen2-1] != '\0')
520     return GNUNET_SYSERR;
521
522   if (addrlen1 != addrlen2)
523     return GNUNET_NO;
524   if (ha1->urlen != ha2->urlen)
525     return GNUNET_NO;
526
527   if (0 == strcmp ((const char *) &ha1[1],(const char *) &ha2[1]))
528     return GNUNET_YES;
529   return GNUNET_NO;
530 }
531
532
533
534 /* end of plugin_transport_http_common.c */