netutils.c 11.6 KB
Newer Older
1
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
2
 * netutils.c: various network functions
3
 *****************************************************************************
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 * Copyright (C) 1999, 2000 VideoLAN
 *
 * Authors:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
22
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
23

24
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
25
 * Preamble
26
 *****************************************************************************/
27
28
#include "defs.h"

29
30
31
32
#include <netdb.h>                                        /* gethostbyname() */
#include <stdlib.h>                             /* free(), realloc(), atoi() */
#include <errno.h>                                                /* errno() */
#include <string.h>                                      /* bzero(), bcopy() */
33
34
35
36
37
38

#ifdef SYS_BSD
#include <netinet/in.h>                                    /* struct in_addr */
#include <sys/socket.h>                                   /* struct sockaddr */
#endif

39
40
41
42
#if defined(SYS_LINUX) || defined(SYS_BSD) || defined(SYS_GNU)
#include <arpa/inet.h>                           /* inet_ntoa(), inet_aton() */
#endif

43
44

#ifdef SYS_LINUX
45
#include <sys/ioctl.h>                                            /* ioctl() */
46
47
#include <net/if.h>                            /* interface (arch-dependent) */
#endif
Michel Kaempf's avatar
Michel Kaempf committed
48
49
50
51
52
53
54
55
56
57

#include "config.h"
#include "common.h"
#include "mtime.h"

#include "intf_msg.h"
#include "debug.h"

#include "netutils.h"

58
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
59
 * BuildInetAddr: build an Internet address descriptor
60
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
61
62
63
64
 * Build an internet socket descriptor from a host name, or an ip, and a port.
 * If the address is NULL, then INADDR_ANY will be used, allowing to receive
 * on any address for a local socket. Usually, in this case, 'port' is also null
 * and the function always succeeds.
65
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
66
67
int BuildInetAddr( struct sockaddr_in *p_sa_in, char *psz_in_addr, int i_port )
{
68
    struct hostent *p_hostent;                            /* host descriptor */
Michel Kaempf's avatar
Michel Kaempf committed
69

70
    memset( p_sa_in, 0, sizeof( struct sockaddr_in ) );
71
72
    p_sa_in->sin_family = AF_INET;                                 /* family */
    p_sa_in->sin_port = htons( i_port );                             /* port */
Michel Kaempf's avatar
Michel Kaempf committed
73
74
75

    /* Use INADDR_ANY if psz_in_addr is NULL */
    if( psz_in_addr == NULL )
76
    {
Michel Kaempf's avatar
Michel Kaempf committed
77
        p_sa_in->sin_addr.s_addr = htonl(INADDR_ANY);
78
79
80
    }
    /* Try to convert address directly from in_addr - this will work if
     * psz_in_addr is dotted decimal. */
81
82
83
#ifdef SYS_BEOS
    else if( (p_sa_in->sin_addr.s_addr = inet_addr( psz_in_addr )) == -1 )
#else
Michel Kaempf's avatar
Michel Kaempf committed
84
    else if( !inet_aton( psz_in_addr, &p_sa_in->sin_addr) )
85
#endif
Michel Kaempf's avatar
Michel Kaempf committed
86
87
88
    {
        /* The convertion failed: the address is an host name, which needs
         * to be resolved */
89
        intf_DbgMsg("debug: resolving internet address %s...\n", psz_in_addr);
Michel Kaempf's avatar
Michel Kaempf committed
90
91
92
        if ( (p_hostent = gethostbyname(psz_in_addr)) == NULL)
        {
            intf_ErrMsg("error: unknown host %s\n", psz_in_addr);
93
            return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
94
95
96
        }

        /* Copy the first address of the host in the socket address */
97
        memmove( &p_sa_in->sin_addr, p_hostent->h_addr_list[0], p_hostent->h_length );
Michel Kaempf's avatar
Michel Kaempf committed
98
    }
99
    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
100
101
102
}


103
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
104
 * ServerPort: extract port from a "server:port" adress
105
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
106
107
 * Returns the port number in a "server:port" address and replace the ":" by
 * a NUL character, or returns -1.
108
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
109
110
111
112
113
114
115
116
int ServerPort( char *psz_addr )
{
    char *psz_index;

    /* Scan string for ':' */
    for( psz_index = psz_addr; *psz_index && (*psz_index != ':'); psz_index++ )
    {
        ;
117
118
    }

Michel Kaempf's avatar
Michel Kaempf committed
119
120
121
122
123
124
125
    /* If a port number has been found, convert it and return it */
    if( *psz_index == ':' )
    {
        *psz_index = '\0';
        return( atoi( psz_index + 1 ) );
    }

126
    return( - 1 );
Michel Kaempf's avatar
Michel Kaempf committed
127
128
129
}


130
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
131
 * ReadIfConf: Read the configuration of an interface
132
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
133
 * i_sockfd must reference a socket open as follow: AF_INET, DOCK_DGRAM, 0
134
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
135
int ReadIfConf(int i_sockfd, if_descr_t* p_ifdescr, char* psz_name)
136
{
Michel Kaempf's avatar
Michel Kaempf committed
137
    int i_rc = 0;
138
139
#ifdef SYS_LINUX
    struct ifreq ifr_config;
140

Michel Kaempf's avatar
Michel Kaempf committed
141
142
    ASSERT(p_ifdescr);
    ASSERT(psz_name);
143

Michel Kaempf's avatar
Michel Kaempf committed
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
    /* Which interface are we interested in ? */
    strcpy(ifr_config.ifr_name, psz_name);

    /* Read the flags for that interface */
    i_rc = ioctl(i_sockfd, SIOCGIFFLAGS, (byte_t *)&ifr_config);
    if( !i_rc )
    {
        p_ifdescr->i_flags = ifr_config.ifr_flags;
        intf_DbgMsg("%s flags: 0x%x\n", psz_name, p_ifdescr->i_flags);
    }
    else
    {
        intf_ErrMsg("Cannot read flags for interface %s: %s\n", psz_name,
                    strerror(errno));
        return -1;
    }

161
   /* Read physical address of the interface and store it in our description */
Michel Kaempf's avatar
Michel Kaempf committed
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
    i_rc = ioctl(i_sockfd, SIOCGIFHWADDR, (byte_t *)&ifr_config);
    if( !i_rc )
    {
        memcpy(&p_ifdescr->sa_phys_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr));
        intf_DbgMsg("%s MAC address: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", psz_name,
                    p_ifdescr->sa_phys_addr.sa_data[0]&0xff,
                    p_ifdescr->sa_phys_addr.sa_data[1]&0xff,
                    p_ifdescr->sa_phys_addr.sa_data[2]&0xff,
                    p_ifdescr->sa_phys_addr.sa_data[3]&0xff,
                    p_ifdescr->sa_phys_addr.sa_data[4]&0xff,
                    p_ifdescr->sa_phys_addr.sa_data[5]&0xff);
    }
    else
    {
        intf_ErrMsg("Cannot read hardware address for interface %s: %s\n",
                    psz_name, strerror(errno));
        return -1;
    }
180

Michel Kaempf's avatar
Michel Kaempf committed
181
182
183
184
185
186
187
188
189
190
191
192
193
194
    /* Read IP address of the interface and store it in our description */
    i_rc = ioctl(i_sockfd, SIOCGIFADDR, (byte_t *)&ifr_config);
    if( !i_rc )
    {
        memcpy(&p_ifdescr->sa_net_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr));
        intf_DbgMsg("%s IP address: %s\n", psz_name,
                    inet_ntoa(p_ifdescr->sa_net_addr.sin_addr));
    }
    else
    {
        intf_ErrMsg("Cannot read network address for interface %s: %s\n",
                    psz_name, strerror(errno));
        return -1;
    }
195
196

  /* Read broadcast address of the interface and store it in our description */
Michel Kaempf's avatar
Michel Kaempf committed
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
    if(p_ifdescr->i_flags & IFF_POINTOPOINT)
    {
        intf_DbgMsg("%s doen't not support broadcast\n", psz_name);
        i_rc = ioctl(i_sockfd, SIOCGIFDSTADDR, (byte_t *)&ifr_config);
    }
    else
    {
        intf_DbgMsg("%s supports broadcast\n", psz_name);
        i_rc = ioctl(i_sockfd, SIOCGIFBRDADDR, (byte_t *)&ifr_config);
    }
    if( !i_rc )
    {
        memcpy(&p_ifdescr->sa_bcast_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr));
        intf_DbgMsg("%s broadcast address: %s\n", psz_name,
                    inet_ntoa(p_ifdescr->sa_bcast_addr.sin_addr));
    }
    else
    {
        intf_ErrMsg("Cannot read broadcast address for interface %s: %s\n",
                    psz_name, strerror(errno));
        return -1;
    }
219
#endif /* SYS_LINUX */
220

Michel Kaempf's avatar
Michel Kaempf committed
221
222
223
224
225
    return i_rc;
}



226
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
227
 * ReadNetConf: Retrieve the network configuration of the host
228
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
229
230
 * Only IP interfaces are listed, and only if they are up
 * i_sockfd must reference a socket open as follow: AF_INET, DOCK_DGRAM, 0
231
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
232
233
int ReadNetConf(int i_sockfd, net_descr_t* p_net_descr)
{
234
#ifdef SYS_LINUX
Michel Kaempf's avatar
Michel Kaempf committed
235
236
237
    struct ifreq* a_ifr_ifconf = NULL;
    struct ifreq* p_ifr_current_if;
    struct ifconf ifc_netconf;
238

Michel Kaempf's avatar
Michel Kaempf committed
239
240
    int i_if_number;
    int i_remaining;
241
#endif /* SYS_LINUX */
Michel Kaempf's avatar
Michel Kaempf committed
242
243
    int i_rc = 0;

244
#ifdef SYS_LINUX
Michel Kaempf's avatar
Michel Kaempf committed
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
    ASSERT(p_net_descr);

    /* Start by assuming we have few than 3 interfaces (i_if_number will
       be incremented by 1 when entering the loop) */
    i_if_number = 2;

    /* Retrieve network configuration for that host */
    do
    {
        i_if_number++;
        a_ifr_ifconf = realloc(a_ifr_ifconf, i_if_number*sizeof(struct ifreq));
        ifc_netconf.ifc_len = i_if_number*sizeof(struct ifreq);
        ifc_netconf.ifc_req = a_ifr_ifconf;

        i_rc = ioctl(i_sockfd, SIOCGIFCONF, (byte_t*)&ifc_netconf);
        if( i_rc )
        {
            intf_ErrMsg("Cannot read network configuration: %s\n",
                        strerror(errno));
            break;
        }
    }
    /* If we detected ifc_len interfaces, this may mean that others have
       been missed because the a_ifr_ifconf was to little, so increase
       it's size and retry */
    while( ifc_netconf.ifc_len >= i_if_number*sizeof(struct ifreq) );

    /* No see what we detected */
    if( !i_rc )
    {
        /* Init the given net_descr_t struct */
        p_net_descr->i_if_number = 0;
        p_net_descr->a_if = NULL;

        /* Iterate through the entries of the a_ifr_ifconf table */
        p_ifr_current_if = ifc_netconf.ifc_req;
        for( i_remaining = ifc_netconf.ifc_len / sizeof (struct ifreq);
             i_remaining-- > 0; p_ifr_current_if++ )
        {
            intf_DbgMsg("Found interface %s\n", p_ifr_current_if->ifr_name);

            /* Don't use an interface devoted to an address family other than IP */
            if(p_ifr_current_if->ifr_addr.sa_family != AF_INET)
                continue;

            /* Read the status of this interface */
            if( ioctl(i_sockfd, SIOCGIFFLAGS, (byte_t *)p_ifr_current_if) < 0 )
            {
                intf_ErrMsg("Cannot access interface %s: %s\n",
                            p_ifr_current_if->ifr_name, strerror(errno));
                i_rc = -1;
                break;
            }
            else
            {
                /* Skip this interface if it is not up or if this is a loopback one */
                if( !p_ifr_current_if->ifr_flags & IFF_UP ||
                    p_ifr_current_if->ifr_flags & IFF_LOOPBACK )
                  continue;

                /* Add an entry to the net_descr struct to store the description of
                   that interface */
                p_net_descr->i_if_number++;
                p_net_descr->a_if = realloc(p_net_descr->a_if,
                                            p_net_descr->i_if_number*sizeof(if_descr_t));
310
                /* FIXME: Read the info ?? */
Michel Kaempf's avatar
Michel Kaempf committed
311
312
313
314
315
                i_rc = ReadIfConf(i_sockfd, &p_net_descr->a_if[p_net_descr->i_if_number-1],
                                  p_ifr_current_if->ifr_name);
            }
        }
    }
316

Michel Kaempf's avatar
Michel Kaempf committed
317
318
    /* Don't need the a_ifr_ifconf anymore */
    free( a_ifr_ifconf );
319
320
#endif /* SYS_LINUX */

Michel Kaempf's avatar
Michel Kaempf committed
321
322
323
324
    return i_rc;
}