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