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