]> git.sesse.net Git - vlc/blob - include/network.h
cf176df4a710de57e2c8851a1d416b44a3411f74
[vlc] / include / network.h
1 /*****************************************************************************
2  * network.h: interface to communicate with network plug-ins
3  *****************************************************************************
4  * Copyright (C) 2002-2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *          Laurent Aimar <fenrir@via.ecp.fr>
9  *          RĂ©mi Denis-Courmont <rem # videolan.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 #ifndef __VLC_NETWORK_H
27 # define __VLC_NETWORK_H
28
29 #if defined( WIN32 )
30 #   if defined(UNDER_CE) && defined(sockaddr_storage)
31 #       undef sockaddr_storage
32 #   endif
33 #   include <winsock2.h>
34 #   include <ws2tcpip.h>
35 #else
36 #   if HAVE_SYS_SOCKET_H
37 #      include <sys/socket.h>
38 #   endif
39 #   if HAVE_NETINET_IN_H
40 #      include <netinet/in.h>
41 #   endif
42 #   if HAVE_ARPA_INET_H
43 #      include <arpa/inet.h>
44 #   elif defined( SYS_BEOS )
45 #      include <net/netdb.h>
46 #   endif
47 #   include <netdb.h>
48 #endif
49
50
51 /*****************************************************************************
52  * network_socket_t: structure passed to a network plug-in to define the
53  *                   kind of socket we want
54  *****************************************************************************/
55 struct network_socket_t
56 {
57     const char *psz_bind_addr;
58     int i_bind_port;
59
60     const char *psz_server_addr;
61     int i_server_port;
62
63     int i_ttl;
64
65     int v6only;
66
67     /* Return values */
68     int i_handle;
69     size_t i_mtu;
70 };
71
72 typedef struct
73 {
74     char *psz_protocol;
75     char *psz_username;
76     char *psz_password;
77     char *psz_host;
78     int  i_port;
79
80     char *psz_path;
81
82     char *psz_option;
83     
84     char *psz_buffer; /* to be freed */
85 } vlc_url_t;
86
87 /*****************************************************************************
88  * vlc_UrlParse:
89  *****************************************************************************
90  * option : if != 0 then path is split at this char
91  *
92  * format [protocol://[login[:password]@]][host[:port]]/path[OPTIONoption]
93  *****************************************************************************/
94 static inline void vlc_UrlParse( vlc_url_t *url, const char *psz_url,
95                                  char option )
96 {
97     char *psz_dup;
98     char *psz_parse;
99     char *p;
100
101     url->psz_protocol = NULL;
102     url->psz_username = NULL;
103     url->psz_password = NULL;
104     url->psz_host     = NULL;
105     url->i_port       = 0;
106     url->psz_path     = NULL;
107     url->psz_option   = NULL;
108     
109     if( psz_url == NULL )
110     {
111         url->psz_buffer = NULL;
112         return;
113     }
114     url->psz_buffer = psz_parse = psz_dup = strdup( psz_url );
115
116     p  = strstr( psz_parse, ":/" );
117     if( p != NULL )
118     {
119         /* we have a protocol */
120
121         /* skip :// */
122         *p++ = '\0';
123         if( p[1] == '/' )
124             p += 2;
125         url->psz_protocol = psz_parse;
126         psz_parse = p;
127     }
128     p = strchr( psz_parse, '@' );
129     if( p != NULL )
130     {
131         /* We have a login */
132         url->psz_username = psz_parse;
133         *p++ = '\0';
134
135         psz_parse = strchr( psz_parse, ':' );
136         if( psz_parse != NULL )
137         {
138             /* We have a password */
139             *psz_parse++ = '\0';
140             url->psz_password = psz_parse;
141         }
142
143         psz_parse = p;
144     }
145
146     p = strchr( psz_parse, '/' );
147     if( !p || psz_parse < p )
148     {
149         char *p2;
150
151         /* We have a host[:port] */
152         url->psz_host = strdup( psz_parse );
153         if( p )
154         {
155             url->psz_host[p - psz_parse] = '\0';
156         }
157
158         if( *url->psz_host == '[' )
159         {
160             /* Ipv6 address */
161             p2 = strchr( url->psz_host, ']' );
162             if( p2 )
163             {
164                 p2 = strchr( p2, ':' );
165             }
166         }
167         else
168         {
169             p2 = strchr( url->psz_host, ':' );
170         }
171         if( p2 )
172         {
173             *p2++ = '\0';
174             url->i_port = atoi( p2 );
175         }
176     }
177     psz_parse = p;
178
179     /* Now parse psz_path and psz_option */
180     if( psz_parse )
181     {
182         url->psz_path = psz_parse;
183         if( option != '\0' )
184         {
185             p = strchr( url->psz_path, option );
186             if( p )
187             {
188                 *p++ = '\0';
189                 url->psz_option = p;
190             }
191         }
192     }
193 }
194
195 /*****************************************************************************
196  * vlc_UrlClean:
197  *****************************************************************************
198  *
199  *****************************************************************************/
200 static inline void vlc_UrlClean( vlc_url_t *url )
201 {
202     if( url->psz_buffer ) free( url->psz_buffer );
203     if( url->psz_host )   free( url->psz_host );
204
205     url->psz_protocol = NULL;
206     url->psz_username = NULL;
207     url->psz_password = NULL;
208     url->psz_host     = NULL;
209     url->i_port       = 0;
210     url->psz_path     = NULL;
211     url->psz_option   = NULL;
212
213     url->psz_buffer   = NULL;
214 }
215
216 static inline int isurlsafe( int c )
217 {
218     return ( (unsigned char)( c - 'a' ) < 26 )
219         || ( (unsigned char)( c - 'A' ) < 26 )
220         || ( (unsigned char)( c - '0' ) < 10 )
221         /* Hmm, we should not encode character that are allowed in URLs
222          * (even if they are not URL-safe), nor URL-safe characters.
223          * We still encode some of them because of Microsoft's crap browser.
224          */
225         || ( strchr( "/:.[]-_.", c ) != NULL );
226 }
227
228 /*****************************************************************************
229  * vlc_UrlEncode: 
230  *****************************************************************************
231  * perform URL encoding
232  * (you do NOT want to do URL decoding - it is not reversible - do NOT do it)
233  *****************************************************************************/
234 static inline char *vlc_UrlEncode( const char *psz_url )
235 {
236     char *psz_enc, *out;
237     const unsigned char *in;
238
239     psz_enc = (char *)malloc( 3 * strlen( psz_url ) + 1 );
240     if( psz_enc == NULL )
241         return NULL;
242
243     out = psz_enc;
244     for( in = (const unsigned char *)psz_url; *in; in++ )
245     {
246         unsigned char c = *in;
247
248         if( isurlsafe( c ) )
249             *out++ = (char)c;
250         else
251         {
252             *out++ = '%';
253             *out++ = ( ( c >> 4 ) >= 0xA ) ? 'A' + ( c >> 4 ) - 0xA
254                                            : '0' + ( c >> 4 );
255             *out++ = ( ( c & 0xf ) >= 0xA ) ? 'A' + ( c & 0xf ) - 0xA
256                                            : '0' + ( c & 0xf );
257         }
258     }
259     *out++ = '\0';
260
261     return (char *)realloc( psz_enc, out - psz_enc );
262 }
263
264 /*****************************************************************************
265  * vlc_UrlIsNotEncoded:
266  *****************************************************************************
267  * check if given string is not a valid URL and must hence be encoded
268  *****************************************************************************/
269 #include <ctype.h>
270
271 static inline int vlc_UrlIsNotEncoded( const char *psz_url )
272 {
273     const char *ptr;
274
275     for( ptr = psz_url; *ptr; ptr++ )
276     {
277         char c = *ptr;
278
279         if( c == '%' )
280         {
281             if( !isxdigit( ptr[1] ) || !isxdigit( ptr[2] ) )
282                 return 1; /* not encoded */
283             ptr += 2;
284         }
285         else
286         if( !isurlsafe( c ) )
287             return 1;
288     }
289     return 0; /* looks fine - but maybe it is not encoded */
290 }
291
292 /*****************************************************************************
293  * vlc_b64_encode:
294  *****************************************************************************
295  *
296  *****************************************************************************/
297 static inline char *vlc_b64_encode( char *src )
298 {
299     static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
300                                                                                 
301     char *dst = (char *)malloc( strlen( src ) * 4 / 3 + 12 );
302     char *ret = dst;
303     unsigned i_bits = 0;
304     unsigned i_shift = 0;
305                                                                                 
306     for( ;; )
307     {
308         if( *src )
309         {
310             i_bits = ( i_bits << 8 )|( *src++ );
311             i_shift += 8;
312         }
313         else if( i_shift > 0 )
314         {
315            i_bits <<= 6 - i_shift;
316            i_shift = 6;
317         }
318         else
319         {
320             *dst++ = '=';
321             break;
322         }
323                                                                                 
324         while( i_shift >= 6 )
325         {
326             i_shift -= 6;
327             *dst++ = b64[(i_bits >> i_shift)&0x3f];
328         }
329     }
330                                                                                 
331     *dst++ = '\0';
332                                                                                 
333     return ret;
334 }
335
336 /* Portable networking layer communication */
337 #define net_OpenTCP(a, b, c) __net_OpenTCP(VLC_OBJECT(a), b, c)
338 VLC_EXPORT( int, __net_OpenTCP, ( vlc_object_t *p_this, const char *psz_host, int i_port ) );
339
340 #define net_ListenTCP(a, b, c) __net_ListenTCP(VLC_OBJECT(a), b, c)
341 VLC_EXPORT( int *, __net_ListenTCP, ( vlc_object_t *, const char *, int ) );
342
343 #define net_Accept(a, b, c) __net_Accept(VLC_OBJECT(a), b, c)
344 VLC_EXPORT( int, __net_Accept, ( vlc_object_t *, int *, mtime_t ) );
345
346 #define net_OpenUDP(a, b, c, d, e ) __net_OpenUDP(VLC_OBJECT(a), b, c, d, e)
347 VLC_EXPORT( int, __net_OpenUDP, ( vlc_object_t *p_this, const char *psz_bind, int i_bind, const char *psz_server, int i_server ) );
348
349 VLC_EXPORT( void, net_Close, ( int fd ) );
350 VLC_EXPORT( void, net_ListenClose, ( int *fd ) );
351
352
353 /* Functions to read from or write to the networking layer */
354 struct virtual_socket_t
355 {
356     void *p_sys;
357     int (*pf_recv) ( void *, void *, int );
358     int (*pf_send) ( void *, const void *, int );
359 };
360
361 #define net_Read(a,b,c,d,e,f) __net_Read(VLC_OBJECT(a),b,c,d,e,f)
362 VLC_EXPORT( int, __net_Read, ( vlc_object_t *p_this, int fd, v_socket_t *, uint8_t *p_data, int i_data, vlc_bool_t b_retry ) );
363
364 #define net_ReadNonBlock(a,b,c,d,e,f) __net_ReadNonBlock(VLC_OBJECT(a),b,c,d,e,f)
365 VLC_EXPORT( int, __net_ReadNonBlock, ( vlc_object_t *p_this, int fd, v_socket_t *, uint8_t *p_data, int i_data, mtime_t i_wait ) );
366
367 #define net_Select(a,b,c,d,e,f,g) __net_Select(VLC_OBJECT(a),b,c,d,e,f,g)
368 VLC_EXPORT( int, __net_Select, ( vlc_object_t *p_this, int *pi_fd, v_socket_t **, int i_fd, uint8_t *p_data, int i_data, mtime_t i_wait ) );
369
370 #define net_Write(a,b,c,d,e) __net_Write(VLC_OBJECT(a),b,c,d,e)
371 VLC_EXPORT( int, __net_Write, ( vlc_object_t *p_this, int fd, v_socket_t *, uint8_t *p_data, int i_data ) );
372
373 #define net_Gets(a,b,c) __net_Gets(VLC_OBJECT(a),b,c)
374 VLC_EXPORT( char *, __net_Gets, ( vlc_object_t *p_this, int fd, v_socket_t * ) );
375
376 VLC_EXPORT( int, net_Printf, ( vlc_object_t *p_this, int fd, v_socket_t *, const char *psz_fmt, ... ) );
377
378 #define net_vaPrintf(a,b,c,d,e) __net_vaPrintf(VLC_OBJECT(a),b,c,d,e)
379 VLC_EXPORT( int, __net_vaPrintf, ( vlc_object_t *p_this, int fd, v_socket_t *, const char *psz_fmt, va_list args ) );
380
381
382 #if !HAVE_INET_PTON
383 /* only in core, so no need for C++ extern "C" */
384 int inet_pton(int af, const char *src, void *dst);
385 #endif
386
387
388 /*****************************************************************************
389  * net_StopRecv/Send
390  *****************************************************************************
391  * Wrappers for shutdown()
392  *****************************************************************************/
393 #if defined (SHUT_WR)
394 /* the standard way */
395 # define net_StopSend( fd ) (void)shutdown( fd, SHUT_WR )
396 # define net_StopRecv( fd ) (void)shutdown( fd, SHUT_RD )
397 #elif defined (SD_SEND)
398 /* the Microsoft seemingly-purposedly-different-for-the-sake-of-it way */
399 # define net_StopSend( fd ) (void)shutdown( fd, SD_SEND )
400 # define net_StopRecv( fd ) (void)shutdown( fd, SD_RECEIVE )
401 #else
402 # warning FIXME: implement shutdown on your platform!
403 # define net_StopSend( fd ) (void)0
404 # define net_StopRecv( fd ) (void)0
405 #endif
406
407 /* Portable network names/addresses resolution layer */
408
409 /* GAI error codes */
410 # ifndef EAI_BADFLAGS
411 #  define EAI_BADFLAGS -1
412 # endif
413 # ifndef EAI_NONAME
414 #  define EAI_NONAME -2
415 # endif
416 # ifndef EAI_AGAIN
417 #  define EAI_AGAIN -3
418 # endif
419 # ifndef EAI_FAIL
420 #  define EAI_FAIL -4
421 # endif
422 # ifndef EAI_NODATA
423 #  define EAI_NODATA -5
424 # endif
425 # ifndef EAI_FAMILY
426 #  define EAI_FAMILY -6
427 # endif
428 # ifndef EAI_SOCKTYPE
429 #  define EAI_SOCKTYPE -7
430 # endif
431 # ifndef EAI_SERVICE
432 #  define EAI_SERVICE -8
433 # endif
434 # ifndef EAI_ADDRFAMILY
435 #  define EAI_ADDRFAMILY -9
436 # endif
437 # ifndef EAI_MEMORY
438 #  define EAI_MEMORY -10
439 # endif
440 # ifndef EAI_SYSTEM
441 #  define EAI_SYSTEM -11
442 # endif
443
444
445 # ifndef NI_MAXHOST
446 #  define NI_MAXHOST 1025
447 #  define NI_MAXSERV 32
448 # endif
449 # define NI_MAXNUMERICHOST 64
450
451 # ifndef NI_NUMERICHOST
452 #  define NI_NUMERICHOST 0x01
453 #  define NI_NUMERICSERV 0x02
454 #  define NI_NOFQDN      0x04
455 #  define NI_NAMEREQD    0x08
456 #  define NI_DGRAM       0x10
457 # endif
458
459 # ifndef HAVE_STRUCT_ADDRINFO
460 struct addrinfo
461 {
462     int ai_flags;
463     int ai_family;
464     int ai_socktype;
465     int ai_protocol;
466     size_t ai_addrlen;
467     struct sockaddr *ai_addr;
468     char *ai_canonname;
469     struct addrinfo *ai_next;
470 };
471 #  define AI_PASSIVE     1
472 #  define AI_CANONNAME   2
473 #  define AI_NUMERICHOST 4
474 # endif /* if !HAVE_STRUCT_ADDRINFO */
475
476 /*** libidn support ***/
477 # ifndef AI_IDN
478 #  define AI_IDN      0
479 #  define AI_CANONIDN 0
480 # endif
481
482 VLC_EXPORT( const char *, vlc_gai_strerror, ( int ) );
483 VLC_EXPORT( int, vlc_getnameinfo, ( const struct sockaddr *, int, char *, int, int *, int ) );
484 VLC_EXPORT( int, vlc_getaddrinfo, ( vlc_object_t *, const char *, int, const struct addrinfo *, struct addrinfo ** ) );
485 VLC_EXPORT( void, vlc_freeaddrinfo, ( struct addrinfo * ) );
486
487 /*****************************************************************************
488  * net_AddressIsMulticast: This function returns VLC_FALSE if the psz_addr does
489  * not specify a multicast address or if the address is not a valid address.
490  *****************************************************************************/
491 static inline vlc_bool_t net_AddressIsMulticast( vlc_object_t *p_object, const char *psz_addr )
492 {
493     struct addrinfo hints, *res;
494     vlc_bool_t b_multicast = VLC_FALSE;
495     int i;
496
497     memset( &hints, 0, sizeof( hints ) );
498     hints.ai_socktype = SOCK_DGRAM; /* UDP */
499     hints.ai_flags = AI_NUMERICHOST;
500
501     i = vlc_getaddrinfo( p_object, psz_addr, 0,
502                          &hints, &res );
503     if( i )
504     {
505         msg_Err( p_object, "Invalid node for net_AddressIsMulticast: %s : %s",
506                  psz_addr, vlc_gai_strerror( i ) );
507         return VLC_FALSE;
508     }
509     
510     if( res->ai_family == AF_INET )
511     {
512 #if !defined( SYS_BEOS )
513         struct sockaddr_in *v4 = (struct sockaddr_in *) res->ai_addr;
514         b_multicast = ( ntohl( v4->sin_addr.s_addr ) >= 0xe0000000 )
515                    && ( ntohl( v4->sin_addr.s_addr ) <= 0xefffffff );
516 #endif
517     }
518     else if( res->ai_family == AF_INET6 )
519     {
520 #if defined( WIN32 ) || defined( HAVE_GETADDRINFO )
521         struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)res->ai_addr;
522         b_multicast = IN6_IS_ADDR_MULTICAST( &v6->sin6_addr );
523 #endif
524     }
525     
526     vlc_freeaddrinfo( res );
527     return b_multicast;
528 }
529
530 static inline int net_GetSockAddress( int fd, char *address, int *port )
531 {
532     struct sockaddr_storage addr;
533     socklen_t addrlen = sizeof( addr );
534
535     return getpeername( fd, (struct sockaddr *)&addr, &addrlen )
536         || vlc_getnameinfo( (struct sockaddr *)&addr, addrlen, address,
537                             NI_MAXNUMERICHOST, port, NI_NUMERICHOST )
538         ? VLC_EGENERIC : 0;
539 }
540
541 static inline int net_GetPeerAddress( int fd, char *address, int *port )
542 {
543     struct sockaddr_storage addr;
544     socklen_t addrlen = sizeof( addr );
545
546     return getpeername( fd, (struct sockaddr *)&addr, &addrlen )
547         || vlc_getnameinfo( (struct sockaddr *)&addr, addrlen, address,
548                             NI_MAXNUMERICHOST, port, NI_NUMERICHOST )
549         ? VLC_EGENERIC : 0;
550 }
551
552 #endif