]> git.sesse.net Git - vlc/blob - src/misc/netutils.c
The motion compensation routines are now modules as well ; choose your
[vlc] / src / misc / netutils.c
1 /*****************************************************************************
2  * netutils.c: various network functions
3  *****************************************************************************
4  * Copyright (C) 1999, 2000 VideoLAN
5  *
6  * Authors: Vincent Seguin <seguin@via.ecp.fr>
7  *          Benoit Steiner <benny@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include "defs.h"
28
29 #include <netdb.h>                                        /* gethostbyname() */
30 #include <stdlib.h>                             /* free(), realloc(), atoi() */
31 #include <errno.h>                                                /* errno() */
32 #include <string.h>                                      /* bzero(), bcopy() */
33
34 #include <netinet/in.h>                               /* BSD: struct in_addr */
35 #include <sys/socket.h>                              /* BSD: struct sockaddr */
36 #ifdef HAVE_ARPA_INET_H
37 #include <arpa/inet.h>                           /* inet_ntoa(), inet_aton() */
38 #endif
39
40 #if defined (HAVE_SYS_IOCTL_H)
41 #include <sys/ioctl.h>                                            /* ioctl() */
42 #endif
43
44 #include <unistd.h>                           /* needed for ioctl on Solaris */
45 //#include <stropts.h>
46
47 #if defined (HAVE_NET_IF_H)
48 #include <net/if.h>                            /* interface (arch-dependent) */
49 #endif
50 #ifdef HAVE_SYS_SOCKIO_H
51 #include <sys/sockio.h>
52 #endif
53
54 #include "config.h"
55 #include "common.h"
56 #include "mtime.h"
57
58 #include "intf_msg.h"
59 #include "debug.h"
60
61 #include "netutils.h"
62
63 /*****************************************************************************
64  * BuildInetAddr: build an Internet address descriptor
65  *****************************************************************************
66  * Build an internet socket descriptor from a host name, or an ip, and a port.
67  * If the address is NULL, then INADDR_ANY will be used, allowing to receive
68  * on any address for a local socket. Usually, in this case, 'port' is also null
69  * and the function always succeeds.
70  *****************************************************************************/
71 int BuildInetAddr( struct sockaddr_in *p_sa_in, char *psz_in_addr, int i_port )
72 {
73     struct hostent *p_hostent;                            /* host descriptor */
74
75     memset( p_sa_in, 0, sizeof( struct sockaddr_in ) );
76     p_sa_in->sin_family = AF_INET;                                 /* family */
77     p_sa_in->sin_port = htons( i_port );                             /* port */
78
79     /* Use INADDR_ANY if psz_in_addr is NULL */
80     if( psz_in_addr == NULL )
81     {
82         p_sa_in->sin_addr.s_addr = htonl(INADDR_ANY);
83     }
84     /* Try to convert address directly from in_addr - this will work if
85      * psz_in_addr is dotted decimal. */
86 #if defined HAVE_ARPA_INET_H && !defined SYS_SOLARIS2_6
87     else if( !inet_aton( psz_in_addr, &p_sa_in->sin_addr) )
88 #else
89     else if( (p_sa_in->sin_addr.s_addr = inet_addr( psz_in_addr )) == -1 )
90 #endif
91     {
92         /* The convertion failed: the address is an host name, which needs
93          * to be resolved */
94         intf_DbgMsg("debug: resolving internet address %s...", psz_in_addr);
95         if ( (p_hostent = gethostbyname(psz_in_addr)) == NULL)
96         {
97             intf_ErrMsg( "net error: unknown host %s", psz_in_addr );
98             return( -1 );
99         }
100
101         /* Copy the first address of the host in the socket address */
102         memmove( &p_sa_in->sin_addr, p_hostent->h_addr_list[0], p_hostent->h_length );
103     }
104     return( 0 );
105 }
106
107
108 /*****************************************************************************
109  * ServerPort: extract port from a "server:port" adress
110  *****************************************************************************
111  * Returns the port number in a "server:port" address and replace the ":" by
112  * a NUL character, or returns -1.
113  *****************************************************************************/
114 int ServerPort( char *psz_addr )
115 {
116     char *psz_index;
117
118     /* Scan string for ':' */
119     for( psz_index = psz_addr; *psz_index && (*psz_index != ':'); psz_index++ )
120     {
121         ;
122     }
123
124     /* If a port number has been found, convert it and return it */
125     if( *psz_index == ':' )
126     {
127         *psz_index = '\0';
128         return( atoi( psz_index + 1 ) );
129     }
130
131     return( - 1 );
132 }
133
134
135 /*****************************************************************************
136  * ReadIfConf: Read the configuration of an interface
137  *****************************************************************************
138  * i_sockfd must reference a socket open as follow: AF_INET, DOCK_DGRAM, 0
139  *****************************************************************************/
140 #if 0
141 /* pbm :  SIOCGIFHWADDR, doesn't exist on BSD -> find a portable way to
142    do this --Meuuh */
143 int ReadIfConf(int i_sockfd, if_descr_t* p_ifdescr, char* psz_name)
144 {
145     int i_rc = 0;
146 #if defined (HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H)
147     struct ifreq ifr_config;
148
149     ASSERT(p_ifdescr);
150     ASSERT(psz_name);
151
152     /* Which interface are we interested in ? */
153     strcpy(ifr_config.ifr_name, psz_name);
154
155     /* Read the flags for that interface */
156     i_rc = ioctl(i_sockfd, SIOCGIFFLAGS, (byte_t *)&ifr_config);
157     if( !i_rc )
158     {
159         p_ifdescr->i_flags = ifr_config.ifr_flags;
160         intf_DbgMsg("%s flags: 0x%x", psz_name, p_ifdescr->i_flags);
161     }
162     else
163     {
164         intf_ErrMsg( "net error: cannot read flags for interface %s (%s)",
165                      psz_name, strerror(errno) );
166         return -1;
167     }
168
169    /* Read physical address of the interface and store it in our description */
170 #ifdef SYS_SOLARIS
171     i_rc = ioctl(i_sockfd, SIOCGENADDR, (byte_t *)&ifr_config);
172 #else
173     i_rc = ioctl(i_sockfd, SIOCGIFHWADDR, (byte_t *)&ifr_config);
174 #endif
175     if( !i_rc )
176     {
177         memcpy(&p_ifdescr->sa_phys_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr));
178         intf_DbgMsg("%s MAC address: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", psz_name,
179                     p_ifdescr->sa_phys_addr.sa_data[0]&0xff,
180                     p_ifdescr->sa_phys_addr.sa_data[1]&0xff,
181                     p_ifdescr->sa_phys_addr.sa_data[2]&0xff,
182                     p_ifdescr->sa_phys_addr.sa_data[3]&0xff,
183                     p_ifdescr->sa_phys_addr.sa_data[4]&0xff,
184                     p_ifdescr->sa_phys_addr.sa_data[5]&0xff);
185     }
186     else
187     {
188         intf_ErrMsg( "net error: cannot read hardware address for %s (%s)",
189                      psz_name, strerror(errno) );
190         return -1;
191     }
192
193     /* Read IP address of the interface and store it in our description */
194     i_rc = ioctl(i_sockfd, SIOCGIFADDR, (byte_t *)&ifr_config);
195     if( !i_rc )
196     {
197         memcpy(&p_ifdescr->sa_net_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr));
198         intf_DbgMsg("%s IP address: %s", psz_name,
199                     inet_ntoa(p_ifdescr->sa_net_addr.sin_addr));
200     }
201     else
202     {
203         intf_ErrMsg( "net error: cannot read network address for %s (%s)",
204                      psz_name, strerror(errno) );
205         return -1;
206     }
207
208   /* Read broadcast address of the interface and store it in our description */
209     if(p_ifdescr->i_flags & IFF_POINTOPOINT)
210     {
211         intf_DbgMsg("%s doen't not support broadcast", psz_name);
212         i_rc = ioctl(i_sockfd, SIOCGIFDSTADDR, (byte_t *)&ifr_config);
213     }
214     else
215     {
216         intf_DbgMsg("%s supports broadcast", psz_name);
217         i_rc = ioctl(i_sockfd, SIOCGIFBRDADDR, (byte_t *)&ifr_config);
218     }
219     if( !i_rc )
220     {
221         memcpy(&p_ifdescr->sa_bcast_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr));
222         intf_DbgMsg("%s broadcast address: %s", psz_name,
223                     inet_ntoa(p_ifdescr->sa_bcast_addr.sin_addr));
224     }
225     else
226     {
227         intf_ErrMsg( "net error: cannot read broadcast address for %s (%s)",
228                      psz_name, strerror(errno));
229         return -1;
230     }
231 #endif
232
233     return i_rc;
234 }
235
236
237 /*****************************************************************************
238  * ReadNetConf: Retrieve the network configuration of the host
239  *****************************************************************************
240  * Only IP interfaces are listed, and only if they are up
241  * i_sockfd must reference a socket open as follow: AF_INET, DOCK_DGRAM, 0
242  *****************************************************************************/
243 int ReadNetConf(int i_sockfd, net_descr_t* p_net_descr)
244 {
245     int i_rc = 0;
246
247 #if defined (HAVE_SYS_IOCTL_H) && defined (HAVE_NET_IF_H)
248     struct ifreq* a_ifr_ifconf = NULL;
249     struct ifreq* p_ifr_current_if;
250     struct ifconf ifc_netconf;
251
252     int i_if_number;
253     int i_remaining;
254
255     ASSERT(p_net_descr);
256
257     /* Start by assuming we have few than 3 interfaces (i_if_number will
258        be incremented by 1 when entering the loop) */
259     i_if_number = 2;
260
261     /* Retrieve network configuration for that host */
262     do
263     {
264         i_if_number++;
265         a_ifr_ifconf = realloc(a_ifr_ifconf, i_if_number*sizeof(struct ifreq));
266         ifc_netconf.ifc_len = i_if_number*sizeof(struct ifreq);
267         ifc_netconf.ifc_req = a_ifr_ifconf;
268
269         i_rc = ioctl(i_sockfd, SIOCGIFCONF, (byte_t*)&ifc_netconf);
270         if( i_rc )
271         {
272             intf_ErrMsg( "net error: cannot read network configuration (%s)",
273                          strerror(errno));
274             break;
275         }
276     }
277     /* If we detected ifc_len interfaces, this may mean that others have
278        been missed because the a_ifr_ifconf was to little, so increase
279        it's size and retry */
280     while( ifc_netconf.ifc_len >= i_if_number*sizeof(struct ifreq) );
281
282     /* No see what we detected */
283     if( !i_rc )
284     {
285         /* Init the given net_descr_t struct */
286         p_net_descr->i_if_number = 0;
287         p_net_descr->a_if = NULL;
288
289         /* Iterate through the entries of the a_ifr_ifconf table */
290         p_ifr_current_if = ifc_netconf.ifc_req;
291         for( i_remaining = ifc_netconf.ifc_len / sizeof (struct ifreq);
292              i_remaining-- > 0; p_ifr_current_if++ )
293         {
294             intf_DbgMsg("Found interface %s", p_ifr_current_if->ifr_name);
295
296             /* Don't use an interface devoted to an address family other than IP */
297             if(p_ifr_current_if->ifr_addr.sa_family != AF_INET)
298                 continue;
299
300             /* Read the status of this interface */
301             if( ioctl(i_sockfd, SIOCGIFFLAGS, (byte_t *)p_ifr_current_if) < 0 )
302             {
303                 intf_ErrMsg( "net error: cannot access interface %s (%s)",
304                              p_ifr_current_if->ifr_name, strerror(errno) );
305                 i_rc = -1;
306                 break;
307             }
308             else
309             {
310                 /* Skip this interface if it is not up or if this is a loopback one */
311                 if( !p_ifr_current_if->ifr_flags & IFF_UP ||
312                     p_ifr_current_if->ifr_flags & IFF_LOOPBACK )
313                   continue;
314
315                 /* Add an entry to the net_descr struct to store the description of
316                    that interface */
317                 p_net_descr->i_if_number++;
318                 p_net_descr->a_if = realloc(p_net_descr->a_if,
319                                             p_net_descr->i_if_number*sizeof(if_descr_t));
320                 /* FIXME: Read the info ?? */
321                 i_rc = ReadIfConf(i_sockfd, &p_net_descr->a_if[p_net_descr->i_if_number-1],
322                                   p_ifr_current_if->ifr_name);
323             }
324         }
325     }
326
327     /* Don't need the a_ifr_ifconf anymore */
328     free( a_ifr_ifconf );
329 #endif
330
331     return i_rc;
332 }
333
334
335 #endif