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