Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

ipv6.c

00001 /*****************************************************************************
00002  * ipv6.c: IPv6 network abstraction layer
00003  *****************************************************************************
00004  * Copyright (C) 2002-2005 the VideoLAN team
00005  * $Id: ipv6.c 12656 2005-09-22 21:19:33Z gbazin $
00006  *
00007  * Authors: Alexis Guillard <[email protected]>
00008  *          Christophe Massiot <[email protected]>
00009  *          Remco Poortinga <[email protected]>
00010  *          RĂ©mi Denis-Courmont <rem # videolan.org>
00011  *
00012  * This program is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 2 of the License, or
00015  * (at your option) any later version.
00016  * 
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, write to the Free Software
00024  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00025  *****************************************************************************/
00026 
00027 /*****************************************************************************
00028  * Preamble
00029  *****************************************************************************/
00030 #include <stdlib.h>
00031 #include <string.h>
00032 
00033 #include <vlc/vlc.h>
00034 
00035 #include <errno.h>
00036 
00037 #ifdef HAVE_FCNTL_H
00038 #   include <fcntl.h>
00039 #endif
00040 #ifdef HAVE_SYS_TYPES_H
00041 #   include <sys/types.h>
00042 #endif
00043 #ifdef HAVE_UNISTD_H
00044 #   include <unistd.h>
00045 #endif
00046 
00047 #ifdef WIN32
00048 #   include <winsock2.h>
00049 #   include <ws2tcpip.h>
00050 #elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
00051 #   include <netdb.h>                                         /* hostent ... */
00052 #   include <sys/socket.h>
00053 #   include <netinet/in.h>
00054 #endif
00055 
00056 #include "network.h"
00057 
00058 #if defined(WIN32)
00059 static const struct in6_addr in6addr_any = {{IN6ADDR_ANY_INIT}};
00060 /* the following will have to be removed when w32api defines them */
00061 #   ifndef IPPROTO_IPV6
00062 #      define IPPROTO_IPV6 41 
00063 #   endif
00064 #   ifndef IPV6_JOIN_GROUP
00065 #      define IPV6_JOIN_GROUP 12
00066 #   endif
00067 #   ifndef IPV6_MULTICAST_HOPS
00068 #      define IPV6_MULTICAST_HOPS 10
00069 #   endif
00070 #   ifndef IPV6_UNICAST_HOPS
00071 #      define IPV6_UNICAST_HOPS 4
00072 #   endif
00073 #   define close closesocket
00074 #endif
00075 
00076 #ifndef MCAST_JOIN_SOURCE_GROUP
00077 #   define MCAST_JOIN_SOURCE_GROUP         46
00078 struct group_source_req
00079 {
00080        uint32_t           gsr_interface;  /* interface index */
00081        struct sockaddr_storage gsr_group;      /* group address */
00082        struct sockaddr_storage gsr_source;     /* source address */
00083 };
00084 #endif
00085 
00086 /*****************************************************************************
00087  * Local prototypes
00088  *****************************************************************************/
00089 static int OpenUDP( vlc_object_t * );
00090 
00091 /*****************************************************************************
00092  * Module descriptor
00093  *****************************************************************************/
00094 vlc_module_begin();
00095     set_description( _("UDP/IPv6 network abstraction layer") );
00096     set_capability( "network", 40 );
00097     set_callbacks( OpenUDP, NULL );
00098 vlc_module_end();
00099 
00100 /*****************************************************************************
00101  * BuildAddr: utility function to build a struct sockaddr_in6
00102  *****************************************************************************/
00103 static int BuildAddr( vlc_object_t *p_this, struct sockaddr_in6 *p_socket,
00104                       const char *psz_address, int i_port )
00105 {
00106     struct addrinfo hints, *res;
00107     int i;
00108 
00109     memset( &hints, 0, sizeof( hints ) );
00110     hints.ai_family = AF_INET6;
00111     hints.ai_socktype = SOCK_DGRAM;
00112     hints.ai_flags = AI_PASSIVE;
00113 
00114     i = vlc_getaddrinfo( p_this, psz_address, 0, &hints, &res );
00115     if( i )
00116     {
00117         msg_Dbg( p_this, "%s: %s", psz_address, vlc_gai_strerror( i ) );
00118         return -1;
00119     }
00120     if ( res->ai_addrlen > sizeof (struct sockaddr_in6) )
00121     {
00122         vlc_freeaddrinfo( res );
00123         return -1;
00124     }
00125 
00126     memcpy( p_socket, res->ai_addr, res->ai_addrlen );
00127     vlc_freeaddrinfo( res );
00128     p_socket->sin6_port = htons( i_port );
00129 
00130     return 0;
00131 }
00132 
00133 #if defined(WIN32) || defined(UNDER_CE)
00134 # define WINSOCK_STRERROR_SIZE 20
00135 static const char *winsock_strerror( char *buf )
00136 {
00137     snprintf( buf, WINSOCK_STRERROR_SIZE, "Winsock error %d",
00138               WSAGetLastError( ) );
00139     buf[WINSOCK_STRERROR_SIZE - 1] = '\0';
00140     return buf;
00141 }
00142 #endif
00143 
00144 
00145 /*****************************************************************************
00146  * OpenUDP: open a UDP socket
00147  *****************************************************************************
00148  * psz_bind_addr, i_bind_port : address and port used for the bind()
00149  *   system call. If psz_bind_addr == NULL, the socket is bound to
00150  *   in6addr_any and broadcast reception is enabled. If psz_bind_addr is a
00151  *   multicast (FF00::/8) address, join the multicast group.
00152  * psz_server_addr, i_server_port : address and port used for the connect()
00153  *   system call. It can avoid receiving packets from unauthorized IPs.
00154  *   Its use leads to great confusion and is currently discouraged.
00155  * This function returns -1 in case of error.
00156  *****************************************************************************/
00157 static int OpenUDP( vlc_object_t * p_this )
00158 {
00159     network_socket_t *p_socket = p_this->p_private;
00160     const char *psz_bind_addr = p_socket->psz_bind_addr;
00161     int i_bind_port = p_socket->i_bind_port;
00162     const char *psz_server_addr = p_socket->psz_server_addr;
00163     int i_server_port = p_socket->i_server_port;
00164     int i_handle, i_opt;
00165     struct sockaddr_in6 sock;
00166     vlc_value_t val;
00167 #if defined(WIN32) || defined(UNDER_CE)
00168     char strerror_buf[WINSOCK_STRERROR_SIZE];
00169 # define strerror( x ) winsock_strerror( strerror_buf )
00170 #endif
00171 
00172     p_socket->i_handle = -1;
00173 
00174     /* Build the local socket */
00175     if ( BuildAddr( p_this, &sock, psz_bind_addr, i_bind_port ) == -1 )        
00176         return 0;
00177 
00178     /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET6 domain, automatic (0)
00179      * protocol */
00180     if( (i_handle = socket( AF_INET6, SOCK_DGRAM, 0 )) == -1 )
00181     {
00182         msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
00183         return 0;
00184     }
00185 
00186 #ifdef IPV6_V6ONLY
00187     val.i_int = p_socket->v6only;
00188 
00189     if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&val.i_int,
00190                     sizeof( val.i_int ) ) )
00191     {
00192         msg_Warn( p_this, "IPV6_V6ONLY: %s", strerror( errno ) );
00193         p_socket->v6only = 1;
00194     }
00195 #else
00196     p_socket->v6only = 1;
00197 #endif
00198 
00199 #ifdef WIN32
00200 # ifndef IPV6_PROTECTION_LEVEL
00201 #   define IPV6_PROTECTION_LEVEL 23
00202 #  endif
00203     {
00204         int i_val = 30 /*PROTECTION_LEVEL_UNRESTRICTED*/;
00205         setsockopt( i_handle, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, &i_val,
00206                     sizeof( i_val ) );
00207     }
00208 #endif
00209 
00210     /* We may want to reuse an already used socket */
00211     i_opt = 1;
00212     if( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR,
00213                     (void *) &i_opt, sizeof( i_opt ) ) == -1 )
00214     {
00215         msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR: %s)",
00216                          strerror(errno) );
00217         close( i_handle );
00218         return 0;
00219     }
00220 
00221     /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
00222      * packet loss caused by scheduling problems */
00223     i_opt = 0x80000;
00224     if( setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF,
00225                     (void *) &i_opt, sizeof( i_opt ) ) == -1 )
00226     {
00227         msg_Warn( p_this, "cannot configure socket (SO_RCVBUF: %s)",
00228                           strerror(errno) );
00229     }
00230 
00231 #if defined(WIN32)
00232     /* Under Win32 and for multicasting, we bind to IN6ADDR_ANY */
00233     if( IN6_IS_ADDR_MULTICAST(&sock.sin6_addr) )
00234     {
00235         struct sockaddr_in6 sockany = sock;
00236         sockany.sin6_addr = in6addr_any;
00237         sockany.sin6_scope_id = 0;
00238 
00239         /* Bind it */
00240         if( bind( i_handle, (struct sockaddr *)&sockany, sizeof( sock ) ) < 0 )
00241         {
00242             msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
00243             close( i_handle );
00244             return 0;
00245         }
00246     }
00247     else
00248 #endif
00249     /* Bind it */
00250     if( bind( i_handle, (struct sockaddr *)&sock, sizeof( sock ) ) < 0 )
00251     {
00252         msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
00253         close( i_handle );
00254         return 0;
00255     }
00256 
00257     /* Allow broadcast reception if we bound on in6addr_any */
00258     if( !*psz_bind_addr )
00259     {
00260         i_opt = 1;
00261         if( setsockopt( i_handle, SOL_SOCKET, SO_BROADCAST,
00262                         (void*) &i_opt, sizeof( i_opt ) ) == -1 )
00263         {
00264             msg_Warn( p_this, "IPv6 warning: cannot configure socket "
00265                               "(SO_BROADCAST: %s)", strerror(errno) );
00266         }
00267     }
00268 
00269     /* Join the multicast group if the socket is a multicast address */
00270 #if defined( WIN32 ) || defined( HAVE_IF_NAMETOINDEX )
00271     if( IN6_IS_ADDR_MULTICAST(&sock.sin6_addr) )
00272     {
00273         if(*psz_server_addr)
00274         {
00275             struct group_source_req imr;
00276             struct sockaddr_in6 *p_sin6;
00277 
00278             imr.gsr_interface = 0;
00279             imr.gsr_group.ss_family = AF_INET6;
00280             imr.gsr_source.ss_family = AF_INET6;
00281             p_sin6 = (struct sockaddr_in6 *)&imr.gsr_group;
00282             p_sin6->sin6_addr = sock.sin6_addr;
00283 
00284             /* Build socket for remote connection */
00285             msg_Dbg( p_this, "psz_server_addr : %s", psz_server_addr);
00286 
00287             if ( BuildAddr( p_this, &sock, psz_server_addr, i_server_port ) )
00288             {
00289                 msg_Warn( p_this, "cannot build remote address" );
00290                 close( i_handle );
00291                 return 0;
00292             }
00293             p_sin6 = (struct sockaddr_in6 *)&imr.gsr_source;
00294             p_sin6->sin6_addr = sock.sin6_addr;
00295 
00296             msg_Dbg( p_this, "IPV6_ADD_SOURCE_MEMBERSHIP multicast request" );
00297             if( setsockopt( i_handle, IPPROTO_IPV6, MCAST_JOIN_SOURCE_GROUP,
00298                           (char *)&imr, sizeof(struct group_source_req) ) == -1 )
00299             {
00300 
00301                 msg_Err( p_this, "failed to join IP multicast group (%s)",
00302                                                           strerror(errno) );
00303             }    
00304         }
00305         else
00306         {
00307         
00308             struct ipv6_mreq     imr;
00309             int                  res;
00310 
00311             imr.ipv6mr_interface = sock.sin6_scope_id;
00312             imr.ipv6mr_multiaddr = sock.sin6_addr;
00313             res = setsockopt(i_handle, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void*) &imr,
00314 #if defined(WIN32)
00315                          sizeof(imr) + 4); /* Doesn't work without this */
00316 #else
00317                          sizeof(imr));
00318 #endif
00319 
00320             if( res == -1 )
00321             {
00322                 msg_Err( p_this, "cannot join multicast group" );
00323             } 
00324         }
00325     }
00326 #else
00327     msg_Warn( p_this, "Multicast IPv6 is not supported on your OS" );
00328 #endif
00329 
00330 
00331     if( *psz_server_addr )
00332     {
00333         int ttl = p_socket->i_ttl;
00334         if( ttl < 1 )
00335         {
00336             ttl = config_GetInt( p_this, "ttl" );
00337         }
00338         if( ttl < 1 ) ttl = 1;
00339 
00340         /* Build socket for remote connection */
00341         if ( BuildAddr( p_this, &sock, psz_server_addr, i_server_port ) == -1 )
00342         {
00343             msg_Warn( p_this, "cannot build remote address" );
00344             close( i_handle );
00345             return 0;
00346         }
00347 
00348         /* Connect the socket */
00349         if( connect( i_handle, (struct sockaddr *) &sock,
00350                      sizeof( sock ) ) == (-1) )
00351         {
00352             msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
00353             close( i_handle );
00354             return 0;
00355         }
00356 
00357         /* Set the time-to-live */
00358         if( ttl > 1 )
00359         {
00360 #if defined( WIN32 ) || defined( HAVE_IF_NAMETOINDEX )
00361             if( IN6_IS_ADDR_MULTICAST(&sock.sin6_addr) )
00362             {
00363                 if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
00364                                 (void *)&ttl, sizeof( ttl ) ) < 0 )
00365                 {
00366                     msg_Err( p_this, "failed to set multicast ttl (%s)",
00367                              strerror(errno) );
00368                 }
00369             }
00370             else
00371 #endif
00372             {
00373                 if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
00374                                 (void *)&ttl, sizeof( ttl ) ) < 0 )
00375                 {
00376                     msg_Err( p_this, "failed to set unicast ttl (%s)",
00377                               strerror(errno) );
00378                 }
00379             }
00380         }
00381     }
00382 
00383     p_socket->i_handle = i_handle;
00384 
00385     var_Create( p_this, "mtu", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00386     var_Get( p_this, "mtu", &val );
00387     p_socket->i_mtu = val.i_int;
00388 
00389     return 0;
00390 }

Generated on Tue Dec 20 10:14:48 2005 for vlc-0.8.4a by  doxygen 1.4.2