X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=include%2Fnetwork.h;h=7463f6e5b1e34780858f7994941d573b3b533f92;hb=4f86b958a07865f443eef419a6e609f75568492a;hp=4fff09ec989a2d9526decd2cc473bc45a166ef5b;hpb=c7c72149fb4e283d9b26508578e0fa95f48f031d;p=vlc diff --git a/include/network.h b/include/network.h index 4fff09ec98..7463f6e5b1 100644 --- a/include/network.h +++ b/include/network.h @@ -1,12 +1,12 @@ /***************************************************************************** * network.h: interface to communicate with network plug-ins ***************************************************************************** - * Copyright (C) 2002-2005 VideoLAN + * Copyright (C) 2002-2005 the VideoLAN team * $Id$ * * Authors: Christophe Massiot * Laurent Aimar - * Rémi Denis-Courmont + * Rémi Denis-Courmont * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,47 +20,77 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #ifndef __VLC_NETWORK_H # define __VLC_NETWORK_H + +#if defined( WIN32 ) +# if defined(UNDER_CE) && defined(sockaddr_storage) +# undef sockaddr_storage +# endif +# if defined(UNDER_CE) +# define HAVE_STRUCT_ADDRINFO +# else +# include +# endif +# include +# include +# define ENETUNREACH WSAENETUNREACH +#else +# if HAVE_SYS_SOCKET_H +# include +# endif +# if HAVE_NETINET_IN_H +# include +# endif +# if HAVE_ARPA_INET_H +# include +# elif defined( SYS_BEOS ) +# include +# endif +# include +#endif + +# ifdef __cplusplus +extern "C" { +# endif + /***************************************************************************** * network_socket_t: structure passed to a network plug-in to define the * kind of socket we want *****************************************************************************/ struct network_socket_t { - unsigned int i_type; - - char * psz_bind_addr; + const char *psz_bind_addr; int i_bind_port; - char * psz_server_addr; + const char *psz_server_addr; int i_server_port; int i_ttl; + int v6only; + /* Return values */ int i_handle; size_t i_mtu; }; -/* Socket types */ -#define NETWORK_UDP 1 -#define NETWORK_TCP 2 -#define NETWORK_TCP_PASSIVE 3 - - typedef struct { char *psz_protocol; + char *psz_username; + char *psz_password; char *psz_host; int i_port; char *psz_path; char *psz_option; + + char *psz_buffer; /* to be freed */ } vlc_url_t; /***************************************************************************** @@ -68,33 +98,56 @@ typedef struct ***************************************************************************** * option : if != 0 then path is split at this char * - * format [protocol://][host[:port]]/path[OPTIONoption] + * format [protocol://[login[:password]@]][host[:port]]/path[OPTIONoption] *****************************************************************************/ -static inline void vlc_UrlParse( vlc_url_t *url, char *psz_url, char option ) +static inline void vlc_UrlParse( vlc_url_t *url, const char *psz_url, + char option ) { - char *psz_dup = psz_url ? strdup( psz_url ) : 0; - char *psz_parse = psz_dup; + char *psz_dup; + char *psz_parse; char *p; url->psz_protocol = NULL; + url->psz_username = NULL; + url->psz_password = NULL; url->psz_host = NULL; url->i_port = 0; url->psz_path = NULL; url->psz_option = NULL; - if( !psz_url ) return; + if( psz_url == NULL ) + { + url->psz_buffer = NULL; + return; + } + url->psz_buffer = psz_parse = psz_dup = strdup( psz_url ); - if( ( p = strstr( psz_parse, ":/" ) ) ) + p = strstr( psz_parse, ":/" ); + if( p != NULL ) { /* we have a protocol */ /* skip :// */ *p++ = '\0'; - if( p[0] == '/' && p[1] == '/' ) - { + if( p[1] == '/' ) p += 2; + url->psz_protocol = psz_parse; + psz_parse = p; + } + p = strchr( psz_parse, '@' ); + if( p != NULL ) + { + /* We have a login */ + url->psz_username = psz_parse; + *p++ = '\0'; + + psz_parse = strchr( psz_parse, ':' ); + if( psz_parse != NULL ) + { + /* We have a password */ + *psz_parse++ = '\0'; + url->psz_password = psz_parse; } - url->psz_protocol = strdup( psz_dup ); psz_parse = p; } @@ -135,18 +188,17 @@ static inline void vlc_UrlParse( vlc_url_t *url, char *psz_url, char option ) /* Now parse psz_path and psz_option */ if( psz_parse ) { - url->psz_path = strdup( psz_parse ); + url->psz_path = psz_parse; if( option != '\0' ) { p = strchr( url->psz_path, option ); if( p ) { *p++ = '\0'; - url->psz_option = strdup( p ); + url->psz_option = p; } } } - free( psz_dup ); } /***************************************************************************** @@ -156,20 +208,34 @@ static inline void vlc_UrlParse( vlc_url_t *url, char *psz_url, char option ) *****************************************************************************/ static inline void vlc_UrlClean( vlc_url_t *url ) { - if( url->psz_protocol ) free( url->psz_protocol ); - if( url->psz_host ) free( url->psz_host ); - if( url->psz_path ) free( url->psz_path ); - if( url->psz_option ) free( url->psz_option ); + if( url->psz_buffer ) free( url->psz_buffer ); + if( url->psz_host ) free( url->psz_host ); url->psz_protocol = NULL; + url->psz_username = NULL; + url->psz_password = NULL; url->psz_host = NULL; url->i_port = 0; url->psz_path = NULL; url->psz_option = NULL; + + url->psz_buffer = NULL; +} + +static inline int isurlsafe( int c ) +{ + return ( (unsigned char)( c - 'a' ) < 26 ) + || ( (unsigned char)( c - 'A' ) < 26 ) + || ( (unsigned char)( c - '0' ) < 10 ) + /* Hmm, we should not encode character that are allowed in URLs + * (even if they are not URL-safe), nor URL-safe characters. + * We still encode some of them because of Microsoft's crap browser. + */ + || ( strchr( "-_.", c ) != NULL ); } /***************************************************************************** - * vlc_UrlEncode: + * vlc_UrlEncode: ***************************************************************************** * perform URL encoding * (you do NOT want to do URL decoding - it is not reversible - do NOT do it) @@ -177,28 +243,27 @@ static inline void vlc_UrlClean( vlc_url_t *url ) static inline char *vlc_UrlEncode( const char *psz_url ) { char *psz_enc, *out; - const char *in; + const unsigned char *in; psz_enc = (char *)malloc( 3 * strlen( psz_url ) + 1 ); if( psz_enc == NULL ) return NULL; out = psz_enc; - for( in = psz_url; *in; in++ ) + for( in = (const unsigned char *)psz_url; *in; in++ ) { - char c = *in; + unsigned char c = *in; - if( ( c <= 32 ) || ( c == '%' ) || ( c == '?' ) || ( c == '&' ) - || ( c == '+' ) ) + if( isurlsafe( c ) ) + *out++ = (char)c; + else { - *out++ = '%'; + *out++ = '%'; *out++ = ( ( c >> 4 ) >= 0xA ) ? 'A' + ( c >> 4 ) - 0xA : '0' + ( c >> 4 ); *out++ = ( ( c & 0xf ) >= 0xA ) ? 'A' + ( c & 0xf ) - 0xA : '0' + ( c & 0xf ); } - else - *out++ = c; } *out++ = '\0'; @@ -227,72 +292,91 @@ static inline int vlc_UrlIsNotEncoded( const char *psz_url ) ptr += 2; } else - if( c == ' ' ) + if( !isurlsafe( c ) ) return 1; } return 0; /* looks fine - but maybe it is not encoded */ } - + /***************************************************************************** * vlc_b64_encode: ***************************************************************************** * *****************************************************************************/ -static inline char *vlc_b64_encode( unsigned char *src ) +static inline char *vlc_b64_encode( char *src ) { - static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - char *dst = malloc( strlen( src ) * 4 / 3 + 12 ); - char *ret = dst; - unsigned i_bits = 0; - unsigned i_shift = 0; - - for( ;; ) + static const char b64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + size_t len = strlen( src ); + + char *ret; + char *dst = (char *)malloc( ( len + 4 ) * 4 / 3 ); + if( dst == NULL ) + return NULL; + + ret = dst; + + while( len > 0 ) { - if( *src ) - { - i_bits = ( i_bits << 8 )|( *src++ ); - i_shift += 8; - } - else if( i_shift > 0 ) + /* pops (up to) 3 bytes of input */ + uint32_t v = *src++ << 24; + + if( len >= 2 ) { - i_bits <<= 6 - i_shift; - i_shift = 6; + v |= *src++ << 16; + if( len >= 3 ) + v |= *src++ << 8; } - else + + /* pushes (up to) 4 bytes of output */ + while( v ) { - *dst++ = '='; - break; + *dst++ = b64[v >> 26]; + v = v << 6; } - - while( i_shift >= 6 ) + + switch( len ) { - i_shift -= 6; - *dst++ = b64[(i_bits >> i_shift)&0x3f]; + case 1: + *dst++ = '='; + *dst++ = '='; + len--; + break; + + case 2: + *dst++ = '='; + len -= 2; + break; + + default: + len -= 3; } } - - *dst++ = '\0'; - + + *dst = '\0'; + return ret; } -VLC_EXPORT( int, net_ConvertIPv4, ( uint32_t *p_addr, const char * psz_address ) ); - /* Portable networking layer communication */ -#define net_OpenTCP(a, b, c) __net_OpenTCP(VLC_OBJECT(a), b, c) -VLC_EXPORT( int, __net_OpenTCP, ( vlc_object_t *p_this, const char *psz_host, int i_port ) ); +#define net_ConnectTCP(a, b, c) __net_ConnectTCP(VLC_OBJECT(a), b, c) +#define net_OpenTCP(a, b, c) __net_ConnectTCP(VLC_OBJECT(a), b, c) +VLC_EXPORT( int, __net_ConnectTCP, ( vlc_object_t *p_this, const char *psz_host, int i_port ) ); #define net_ListenTCP(a, b, c) __net_ListenTCP(VLC_OBJECT(a), b, c) -VLC_EXPORT( int, __net_ListenTCP, ( vlc_object_t *p_this, char *psz_localaddr, int i_port ) ); +VLC_EXPORT( int *, __net_ListenTCP, ( vlc_object_t *, const char *, int ) ); #define net_Accept(a, b, c) __net_Accept(VLC_OBJECT(a), b, c) -VLC_EXPORT( int, __net_Accept, ( vlc_object_t *p_this, int fd_listen, mtime_t i_wait ) ); +VLC_EXPORT( int, __net_Accept, ( vlc_object_t *, int *, mtime_t ) ); + +#define net_ConnectUDP(a, b, c, d ) __net_ConnectUDP(VLC_OBJECT(a), b, c, d) +VLC_EXPORT( int, __net_ConnectUDP, ( vlc_object_t *p_this, const char *psz_host, int i_port, int hlim ) ); #define net_OpenUDP(a, b, c, d, e ) __net_OpenUDP(VLC_OBJECT(a), b, c, d, e) -VLC_EXPORT( int, __net_OpenUDP, ( vlc_object_t *p_this, char *psz_bind, int i_bind, char *psz_server, int i_server ) ); +VLC_EXPORT( int, __net_OpenUDP, ( vlc_object_t *p_this, const char *psz_bind, int i_bind, const char *psz_server, int i_server ) ); VLC_EXPORT( void, net_Close, ( int fd ) ); +VLC_EXPORT( void, net_ListenClose, ( int *fd ) ); /* Functions to read from or write to the networking layer */ @@ -313,7 +397,7 @@ VLC_EXPORT( int, __net_ReadNonBlock, ( vlc_object_t *p_this, int fd, v_socket_t 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 ) ); #define net_Write(a,b,c,d,e) __net_Write(VLC_OBJECT(a),b,c,d,e) -VLC_EXPORT( int, __net_Write, ( vlc_object_t *p_this, int fd, v_socket_t *, uint8_t *p_data, int i_data ) ); +VLC_EXPORT( int, __net_Write, ( vlc_object_t *p_this, int fd, v_socket_t *, const uint8_t *p_data, int i_data ) ); #define net_Gets(a,b,c) __net_Gets(VLC_OBJECT(a),b,c) VLC_EXPORT( char *, __net_Gets, ( vlc_object_t *p_this, int fd, v_socket_t * ) ); @@ -323,4 +407,175 @@ VLC_EXPORT( int, net_Printf, ( vlc_object_t *p_this, int fd, v_socket_t *, const #define net_vaPrintf(a,b,c,d,e) __net_vaPrintf(VLC_OBJECT(a),b,c,d,e) VLC_EXPORT( int, __net_vaPrintf, ( vlc_object_t *p_this, int fd, v_socket_t *, const char *psz_fmt, va_list args ) ); + +#if !HAVE_INET_PTON +/* only in core, so no need for C++ extern "C" */ +int inet_pton(int af, const char *src, void *dst); +#endif + + +/***************************************************************************** + * net_StopRecv/Send + ***************************************************************************** + * Wrappers for shutdown() + *****************************************************************************/ +#if defined (SHUT_WR) +/* the standard way */ +# define net_StopSend( fd ) (void)shutdown( fd, SHUT_WR ) +# define net_StopRecv( fd ) (void)shutdown( fd, SHUT_RD ) +#elif defined (SD_SEND) +/* the Microsoft seemingly-purposedly-different-for-the-sake-of-it way */ +# define net_StopSend( fd ) (void)shutdown( fd, SD_SEND ) +# define net_StopRecv( fd ) (void)shutdown( fd, SD_RECEIVE ) +#else +# ifndef SYS_BEOS /* R5 just doesn't have a working shutdown() */ +# warning FIXME: implement shutdown on your platform! +# endif +# define net_StopSend( fd ) (void)0 +# define net_StopRecv( fd ) (void)0 +#endif + +/* Portable network names/addresses resolution layer */ + +/* GAI error codes */ +# ifndef EAI_BADFLAGS +# define EAI_BADFLAGS -1 +# endif +# ifndef EAI_NONAME +# define EAI_NONAME -2 +# endif +# ifndef EAI_AGAIN +# define EAI_AGAIN -3 +# endif +# ifndef EAI_FAIL +# define EAI_FAIL -4 +# endif +# ifndef EAI_NODATA +# define EAI_NODATA -5 +# endif +# ifndef EAI_FAMILY +# define EAI_FAMILY -6 +# endif +# ifndef EAI_SOCKTYPE +# define EAI_SOCKTYPE -7 +# endif +# ifndef EAI_SERVICE +# define EAI_SERVICE -8 +# endif +# ifndef EAI_ADDRFAMILY +# define EAI_ADDRFAMILY -9 +# endif +# ifndef EAI_MEMORY +# define EAI_MEMORY -10 +# endif +# ifndef EAI_SYSTEM +# define EAI_SYSTEM -11 +# endif + + +# ifndef NI_MAXHOST +# define NI_MAXHOST 1025 +# define NI_MAXSERV 32 +# endif +# define NI_MAXNUMERICHOST 64 + +# ifndef NI_NUMERICHOST +# define NI_NUMERICHOST 0x01 +# define NI_NUMERICSERV 0x02 +# define NI_NOFQDN 0x04 +# define NI_NAMEREQD 0x08 +# define NI_DGRAM 0x10 +# endif + +# ifndef HAVE_STRUCT_ADDRINFO +struct addrinfo +{ + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + struct sockaddr *ai_addr; + char *ai_canonname; + struct addrinfo *ai_next; +}; +# define AI_PASSIVE 1 +# define AI_CANONNAME 2 +# define AI_NUMERICHOST 4 +# endif /* if !HAVE_STRUCT_ADDRINFO */ + +VLC_EXPORT( const char *, vlc_gai_strerror, ( int ) ); +VLC_EXPORT( int, vlc_getnameinfo, ( const struct sockaddr *, int, char *, int, int *, int ) ); +VLC_EXPORT( int, vlc_getaddrinfo, ( vlc_object_t *, const char *, int, const struct addrinfo *, struct addrinfo ** ) ); +VLC_EXPORT( void, vlc_freeaddrinfo, ( struct addrinfo * ) ); + +/***************************************************************************** + * net_AddressIsMulticast: This function returns VLC_FALSE if the psz_addr does + * not specify a multicast address or if the address is not a valid address. + *****************************************************************************/ +static inline vlc_bool_t net_AddressIsMulticast( vlc_object_t *p_object, const char *psz_addr ) +{ + struct addrinfo hints, *res; + vlc_bool_t b_multicast = VLC_FALSE; + int i; + + memset( &hints, 0, sizeof( hints ) ); + hints.ai_socktype = SOCK_DGRAM; /* UDP */ + hints.ai_flags = AI_NUMERICHOST; + + i = vlc_getaddrinfo( p_object, psz_addr, 0, + &hints, &res ); + if( i ) + { + msg_Err( p_object, "Invalid node for net_AddressIsMulticast: %s : %s", + psz_addr, vlc_gai_strerror( i ) ); + return VLC_FALSE; + } + + if( res->ai_family == AF_INET ) + { +#if !defined( SYS_BEOS ) + struct sockaddr_in *v4 = (struct sockaddr_in *) res->ai_addr; + b_multicast = ( ntohl( v4->sin_addr.s_addr ) >= 0xe0000000 ) + && ( ntohl( v4->sin_addr.s_addr ) <= 0xefffffff ); +#endif + } +#if defined( WIN32 ) || defined( HAVE_GETADDRINFO ) + else if( res->ai_family == AF_INET6 ) + { + struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)res->ai_addr; + b_multicast = IN6_IS_ADDR_MULTICAST( &v6->sin6_addr ); + } +#endif + + vlc_freeaddrinfo( res ); + return b_multicast; +} + +static inline int net_GetSockAddress( int fd, char *address, int *port ) +{ + struct sockaddr_storage addr; + socklen_t addrlen = sizeof( addr ); + + return getsockname( fd, (struct sockaddr *)&addr, &addrlen ) + || vlc_getnameinfo( (struct sockaddr *)&addr, addrlen, address, + NI_MAXNUMERICHOST, port, NI_NUMERICHOST ) + ? VLC_EGENERIC : 0; +} + +static inline int net_GetPeerAddress( int fd, char *address, int *port ) +{ + struct sockaddr_storage addr; + socklen_t addrlen = sizeof( addr ); + + return getpeername( fd, (struct sockaddr *)&addr, &addrlen ) + || vlc_getnameinfo( (struct sockaddr *)&addr, addrlen, address, + NI_MAXNUMERICHOST, port, NI_NUMERICHOST ) + ? VLC_EGENERIC : 0; +} + +# ifdef __cplusplus +} +# endif + #endif