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