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