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