netutils.c 16.6 KB
Newer Older
1
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
2
 * netutils.c: various network functions
3
 *****************************************************************************
4
 * Copyright (C) 1999-2001 VideoLAN
gbazin's avatar
   
gbazin committed
5
 * $Id: netutils.c,v 1.57 2002/02/24 20:51:10 gbazin Exp $
6
 *
7
 * Authors: Vincent Seguin <seguin@via.ecp.fr>
Benoit Steiner's avatar
   
Benoit Steiner committed
8
 *          Benoit Steiner <benny@via.ecp.fr>
Henri Fallon's avatar
   
Henri Fallon committed
9
 *          Henri Fallon <henri@videolan.org>
Xavier Marchesini's avatar
Xavier Marchesini committed
10
 *          Xavier Marchesini <xav@via.ecp.fr>
11
12
 *          Christophe Massiot <massiot@via.ecp.fr>
 *          Samuel Hocevar <sam@via.ecp.fr>
13
14
15
16
17
 *
 * 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.
Sam Hocevar's avatar
   
Sam Hocevar committed
18
 *
19
20
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
23
 *
24
25
26
 * 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, USA.
27
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
28

29
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
30
 * Preamble
31
 *****************************************************************************/
32
33
#include <stdlib.h>                             /* free(), realloc(), atoi() */
#include <errno.h>                                                /* errno() */
Sam Hocevar's avatar
   
Sam Hocevar committed
34
#include <string.h>                                              /* memset() */
Sam Hocevar's avatar
   
Sam Hocevar committed
35

Sam Hocevar's avatar
   
Sam Hocevar committed
36
37
#include <videolan/vlc.h>

Sam Hocevar's avatar
   
Sam Hocevar committed
38
39
40
41
#ifdef STRNCASECMP_IN_STRINGS_H
#   include <strings.h>
#endif

Sam Hocevar's avatar
   
Sam Hocevar committed
42
#ifdef HAVE_UNISTD_H
Sam Hocevar's avatar
   
Sam Hocevar committed
43
#   include <unistd.h>                                      /* gethostname() */
Sam Hocevar's avatar
   
Sam Hocevar committed
44
#elif defined( _MSC_VER ) && defined( _WIN32 )
Sam Hocevar's avatar
   
Sam Hocevar committed
45
#   include <io.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
46
47
48
#endif

#if !defined( _MSC_VER )
Henri Fallon's avatar
   
Henri Fallon committed
49
#include <sys/time.h>                                        /* gettimeofday */
Sam Hocevar's avatar
   
Sam Hocevar committed
50
#endif
51

Sam Hocevar's avatar
   
Sam Hocevar committed
52
53
#ifdef WIN32
#   include <winsock2.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
54
#elif !defined( SYS_BEOS )
Sam Hocevar's avatar
   
Sam Hocevar committed
55
56
57
58
59
60
#   include <netdb.h>                                         /* hostent ... */
#   include <sys/socket.h>                           /* BSD: struct sockaddr */
#   include <netinet/in.h>                            /* BSD: struct in_addr */
#   ifdef HAVE_ARPA_INET_H
#       include <arpa/inet.h>                    /* inet_ntoa(), inet_aton() */
#   endif
61
62
#endif

Henri Fallon's avatar
   
Henri Fallon committed
63
64
65
66
#ifdef SYS_LINUX
#include <sys/ioctl.h>                                            /* ioctl() */
#endif

Sam Hocevar's avatar
   
Sam Hocevar committed
67
#if defined( WIN32 )                    /* tools to get the MAC adress from  */
Sam Hocevar's avatar
   
Sam Hocevar committed
68
#include <windows.h>                    /* the interface under Windows       */
Xavier Marchesini's avatar
Xavier Marchesini committed
69
#include <stdio.h>
gbazin's avatar
   
gbazin committed
70
#include <nb30.h>
Xavier Marchesini's avatar
Xavier Marchesini committed
71
72
#endif

Sam Hocevar's avatar
   
Sam Hocevar committed
73
#ifdef HAVE_NET_IF_H
74
75
#include <net/if.h>                            /* interface (arch-dependent) */
#endif
Henri Fallon's avatar
   
Henri Fallon committed
76

Benoit Steiner's avatar
   
Benoit Steiner committed
77
#ifdef HAVE_SYS_SOCKIO_H
Benoit Steiner's avatar
Benoit Steiner committed
78
#include <sys/sockio.h>
Benoit Steiner's avatar
   
Benoit Steiner committed
79
#endif
Michel Kaempf's avatar
Michel Kaempf committed
80

Sam Hocevar's avatar
   
Sam Hocevar committed
81
#include "netutils.h"
Michel Kaempf's avatar
Michel Kaempf committed
82

Sam Hocevar's avatar
   
Sam Hocevar committed
83
#include "intf_playlist.h"
Michel Kaempf's avatar
Michel Kaempf committed
84

85
/*****************************************************************************
Henri Fallon's avatar
   
Henri Fallon committed
86
87
88
89
90
91
92
93
94
 * input_channel_t: channel library data
 *****************************************************************************
 * Store global channel library data.
 * The part of the code concerning the channel changing process is unstable
 * as it depends on the VideoLAN channel server, which isn't frozen for
 * the time being.
 *****************************************************************************/
typedef struct input_channel_s
{
Sam Hocevar's avatar
   
Sam Hocevar committed
95
    int         i_channel;                         /* current channel number */
Henri Fallon's avatar
   
Henri Fallon committed
96
97
98
    mtime_t     last_change;                             /* last change date */
} input_channel_t;

Xavier Marchesini's avatar
Xavier Marchesini committed
99
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
100
101
 * Local prototypes
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
102
static int GetMacAddress   ( int i_fd, char *psz_mac );
Sam Hocevar's avatar
   
Sam Hocevar committed
103
104
#ifdef WIN32
static int GetAdapterInfo  ( int i_adapter, char *psz_string );
Xavier Marchesini's avatar
Xavier Marchesini committed
105
106
#endif

Henri Fallon's avatar
   
Henri Fallon committed
107
/*****************************************************************************
108
 * network_BuildAddr : fill a sockaddr_in structure
109
 *****************************************************************************/
110
111
int network_BuildAddr( struct sockaddr_in * p_socket,
                       char * psz_address, int i_port )
Michel Kaempf's avatar
Michel Kaempf committed
112
{
Tony Castley's avatar
Tony Castley committed
113
#if defined( SYS_BEOS )
114
    intf_ErrMsg( "error: networking is not yet supported under BeOS" );
Tony Castley's avatar
Tony Castley committed
115
    return( 1 );
Sam Hocevar's avatar
   
Sam Hocevar committed
116
117

#else
Henri Fallon's avatar
   
Henri Fallon committed
118
119
    /* Reset struct */
    memset( p_socket, 0, sizeof( struct sockaddr_in ) );
Sam Hocevar's avatar
   
Sam Hocevar committed
120
    p_socket->sin_family = AF_INET;                                /* family */
Henri Fallon's avatar
   
Henri Fallon committed
121
    p_socket->sin_port = htons( i_port );
122
    if( psz_address == NULL )
Henri Fallon's avatar
   
Henri Fallon committed
123
    {
124
        p_socket->sin_addr.s_addr = INADDR_ANY;
Henri Fallon's avatar
   
Henri Fallon committed
125
126
    }
    else
Sam Hocevar's avatar
   
Sam Hocevar committed
127
    {
128
        struct hostent    * p_hostent;
Henri Fallon's avatar
   
Henri Fallon committed
129

130
131
        /* Try to convert address directly from in_addr - this will work if
         * psz_broadcast is dotted decimal. */
Henri Fallon's avatar
   
Henri Fallon committed
132
#ifdef HAVE_ARPA_INET_H
133
        if( !inet_aton( psz_address, &p_socket->sin_addr) )
134
#else
135
        if( (p_socket->sin_addr.s_addr = inet_addr( psz_address )) == -1 )
136
#endif
Michel Kaempf's avatar
Michel Kaempf committed
137
        {
138
            /* We have a fqdn, try to find its address */
139
            if ( (p_hostent = gethostbyname( psz_address )) == NULL )
140
            {
141
                intf_ErrMsg( "BuildLocalAddr: unknown host %s", psz_address );
142
143
144
145
146
147
                return( -1 );
            }

            /* Copy the first address of the host in the socket address */
            memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0],
                     p_hostent->h_length );
Michel Kaempf's avatar
Michel Kaempf committed
148
149
        }
    }
150
    return( 0 );
Sam Hocevar's avatar
   
Sam Hocevar committed
151
#endif
Michel Kaempf's avatar
Michel Kaempf committed
152
153
}

Henri Fallon's avatar
   
Henri Fallon committed
154
155
156
157
/*****************************************************************************
 * network_ChannelCreate: initialize global channel method data
 *****************************************************************************
 * Initialize channel input method global data. This function should be called
Sam Hocevar's avatar
   
Sam Hocevar committed
158
 * once before any input thread is created or any call to other
Henri Fallon's avatar
   
Henri Fallon committed
159
160
161
162
 * input_Channel*() function is attempted.
 *****************************************************************************/
int network_ChannelCreate( void )
{
Sam Hocevar's avatar
   
Sam Hocevar committed
163
#if defined( SYS_LINUX ) || defined( WIN32 )
Sam Hocevar's avatar
   
Sam Hocevar committed
164

Henri Fallon's avatar
   
Henri Fallon committed
165
166
167
168
    /* Allocate structure */
    p_main->p_channel = malloc( sizeof( input_channel_t ) );
    if( p_main->p_channel == NULL )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
169
        intf_ErrMsg( "network error: could not create channel bank" );
Henri Fallon's avatar
   
Henri Fallon committed
170
171
172
173
        return( -1 );
    }

    /* Initialize structure */
Sam Hocevar's avatar
   
Sam Hocevar committed
174
    p_main->p_channel->i_channel   = 0;
Henri Fallon's avatar
   
Henri Fallon committed
175
176
    p_main->p_channel->last_change = 0;

Sam Hocevar's avatar
   
Sam Hocevar committed
177
    intf_WarnMsg( 2, "network: channels initialized" );
Henri Fallon's avatar
   
Henri Fallon committed
178
    return( 0 );
Sam Hocevar's avatar
   
Sam Hocevar committed
179

Henri Fallon's avatar
   
Henri Fallon committed
180
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
181
    intf_ErrMsg( "network error : channels not supported on this platform" );
Sam Hocevar's avatar
   
Sam Hocevar committed
182
    return( 1 );
Sam Hocevar's avatar
   
Sam Hocevar committed
183
184

#endif
Henri Fallon's avatar
   
Henri Fallon committed
185
186
187
188
189
}

/*****************************************************************************
 * network_ChannelJoin: join a channel
 *****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
190
191
192
193
 * This function will try to join a channel. If the relevant interface is
 * already on the good channel, nothing will be done. Else, and if possible
 * (if the interface is not locked), the channel server will be contacted
 * and a change will be requested. The function will block until the change
Sam Hocevar's avatar
   
Sam Hocevar committed
194
 * is effective. Note that once a channel is no more used, its interface
Henri Fallon's avatar
   
Henri Fallon committed
195
196
197
 * should be unlocked using input_ChannelLeave().
 * Non 0 will be returned in case of error.
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
198
int network_ChannelJoin( int i_channel )
Henri Fallon's avatar
   
Henri Fallon committed
199
{
Sam Hocevar's avatar
   
Sam Hocevar committed
200
201
#if defined( SYS_LINUX ) || defined( WIN32 )

202
#define VLCS_VERSION 13
Sam Hocevar's avatar
   
Sam Hocevar committed
203
#define MESSAGE_LENGTH 256
Sam Hocevar's avatar
   
Sam Hocevar committed
204
205
206
207
208
209
210
211
212

    char psz_mess[ MESSAGE_LENGTH ];
    char psz_mac[ 40 ];
    int i_fd, i_dummy, i_port;
    char *psz_vlcs;
    struct sockaddr_in sa_server;
    struct sockaddr_in sa_client;
    struct timeval delay;
    fd_set fds;
Sam Hocevar's avatar
   
Sam Hocevar committed
213

gbazin's avatar
   
gbazin committed
214
    if( !config_GetIntVariable( INPUT_NETWORK_CHANNEL_VAR ) )
Henri Fallon's avatar
   
Henri Fallon committed
215
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
216
217
        intf_ErrMsg( "network: channels disabled, to enable them, use the"
                     "--channels option" );
Sam Hocevar's avatar
   
Sam Hocevar committed
218
        return -1;
Henri Fallon's avatar
   
Henri Fallon committed
219
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
220

Henri Fallon's avatar
   
Henri Fallon committed
221
222
223
    /* If last change is too recent, wait a while */
    if( mdate() - p_main->p_channel->last_change < INPUT_CHANNEL_CHANGE_DELAY )
    {
224
        intf_WarnMsg( 2, "network: waiting before changing channel" );
Sam Hocevar's avatar
   
Sam Hocevar committed
225
        /* XXX Isn't this completely brain-damaged ??? -- Sam */
Henri Fallon's avatar
   
Henri Fallon committed
226
227
        mwait( p_main->p_channel->last_change + INPUT_CHANNEL_CHANGE_DELAY );
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
228

Sam Hocevar's avatar
   
Sam Hocevar committed
229
230
    /* Initializing the socket */
    i_fd = socket( AF_INET, SOCK_DGRAM, 0 );
Sam Hocevar's avatar
   
Sam Hocevar committed
231
232
233
234
235
236
    if( i_fd < 0 )
    {
        intf_ErrMsg( "network error: unable to create vlcs socket (%s)",
                     strerror( errno ) );
        return -1;
    }
Henri Fallon's avatar
   
Henri Fallon committed
237

Sam Hocevar's avatar
   
Sam Hocevar committed
238
239
240
241
242
243
244
245
246
247
    i_dummy = 1;
    if( setsockopt( i_fd, SOL_SOCKET, SO_REUSEADDR,
                    (void *) &i_dummy, sizeof( i_dummy ) ) == -1 )
    {
        intf_ErrMsg( "network error: can't SO_REUSEADDR vlcs socket (%s)",
                     strerror(errno));
        close( i_fd );
        return -1;
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
248
    /* Getting information about the channel server */
gbazin's avatar
   
gbazin committed
249
250
251
252
253
254
255
256
    if( !(psz_vlcs = config_GetPszVariable( INPUT_CHANNEL_SERVER_VAR )) )
    {
        intf_ErrMsg( "network: configuration variable %s empty",
                     INPUT_CHANNEL_SERVER_VAR );
        return -1;
    }

    i_port = config_GetIntVariable( INPUT_CHANNEL_PORT_VAR );
Henri Fallon's avatar
   
Henri Fallon committed
257

Sam Hocevar's avatar
   
Sam Hocevar committed
258
259
    intf_WarnMsg( 5, "network: socket %i, vlcs '%s', port %d",
                     i_fd, psz_vlcs, i_port );
260

Sam Hocevar's avatar
   
Sam Hocevar committed
261
    memset( &sa_client, 0x00, sizeof(struct sockaddr_in) );
Sam Hocevar's avatar
   
Sam Hocevar committed
262
    memset( &sa_server, 0x00, sizeof(struct sockaddr_in) );
Sam Hocevar's avatar
   
Sam Hocevar committed
263
264
265
266
267
    sa_client.sin_family      = AF_INET;
    sa_server.sin_family      = AF_INET;
    sa_client.sin_port        = htons( 4312 );
    sa_server.sin_port        = htons( i_port );
    sa_client.sin_addr.s_addr = INADDR_ANY;
Sam Hocevar's avatar
   
Sam Hocevar committed
268
#ifdef HAVE_ARPA_INET_H
Sam Hocevar's avatar
   
Sam Hocevar committed
269
    inet_aton( psz_vlcs, &sa_server.sin_addr );
Sam Hocevar's avatar
   
Sam Hocevar committed
270
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
271
    sa_server.sin_addr.s_addr = inet_addr( psz_vlcs );
Sam Hocevar's avatar
   
Sam Hocevar committed
272
#endif
gbazin's avatar
   
gbazin committed
273
    free( psz_vlcs );
Marc Ariberti's avatar
Marc Ariberti committed
274

Sam Hocevar's avatar
   
Sam Hocevar committed
275
    /* Bind the socket */
Sam Hocevar's avatar
   
Sam Hocevar committed
276
    if( bind( i_fd, (struct sockaddr*)(&sa_client), sizeof(sa_client) ) )
Sam Hocevar's avatar
   
Sam Hocevar committed
277
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
278
279
280
        intf_ErrMsg( "network: unable to bind vlcs socket (%s)",
                     strerror( errno ) );
        close( i_fd );
Sam Hocevar's avatar
   
Sam Hocevar committed
281
282
283
284
285
        return -1;
    }

    /* Look for the interface MAC address */
    if( GetMacAddress( i_fd, psz_mac ) )
Henri Fallon's avatar
   
Henri Fallon committed
286
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
287
        intf_ErrMsg( "network error: failed getting MAC address" );
Sam Hocevar's avatar
   
Sam Hocevar committed
288
        close( i_fd );
Sam Hocevar's avatar
   
Sam Hocevar committed
289
        return -1;
Marc Ariberti's avatar
Marc Ariberti committed
290
    }
Henri Fallon's avatar
   
Henri Fallon committed
291

Sam Hocevar's avatar
   
Sam Hocevar committed
292
    intf_WarnMsg( 6, "network: MAC address is %s", psz_mac );
Henri Fallon's avatar
   
Henri Fallon committed
293

Sam Hocevar's avatar
   
Sam Hocevar committed
294
295
    /* Build the message */
    sprintf( psz_mess, "%d %u %lu %s \n", i_channel, VLCS_VERSION,
296
                       (unsigned long)(mdate() / (u64)1000000),
Sam Hocevar's avatar
   
Sam Hocevar committed
297
                       psz_mac );
Sam Hocevar's avatar
   
Sam Hocevar committed
298

Sam Hocevar's avatar
   
Sam Hocevar committed
299
300
301
    /* Send the message */
    sendto( i_fd, psz_mess, MESSAGE_LENGTH, 0,
            (struct sockaddr *)(&sa_server), sizeof(struct sockaddr) );
Henri Fallon's avatar
   
Henri Fallon committed
302

Sam Hocevar's avatar
   
Sam Hocevar committed
303
    intf_WarnMsg( 2, "network: attempting to join channel %d", i_channel );
Henri Fallon's avatar
   
Henri Fallon committed
304

Sam Hocevar's avatar
   
Sam Hocevar committed
305
306
307
    /* We have changed channels ! (or at least, we tried) */
    p_main->p_channel->last_change = mdate();
    p_main->p_channel->i_channel = i_channel;
Sam Hocevar's avatar
   
Sam Hocevar committed
308

Sam Hocevar's avatar
   
Sam Hocevar committed
309
310
311
    /* Wait 5 sec for an answer from the server */
    delay.tv_sec = 5;
    delay.tv_usec = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
312
    FD_ZERO( &fds );
Sam Hocevar's avatar
   
Sam Hocevar committed
313
    FD_SET( i_fd, &fds );
Sam Hocevar's avatar
   
Sam Hocevar committed
314

Sam Hocevar's avatar
   
Sam Hocevar committed
315
    switch( select( i_fd + 1, &fds, NULL, NULL, &delay ) )
Henri Fallon's avatar
   
Henri Fallon committed
316
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
317
318
319
320
321
322
323
324
325
326
327
328
        case 0:
            intf_ErrMsg( "network error: no answer from vlcs" );
            close( i_fd );
            return -1;
            break;

        case -1:
            intf_ErrMsg( "network error: error while listening to vlcs" );
            close( i_fd );
            return -1;
            break;
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
329

Sam Hocevar's avatar
   
Sam Hocevar committed
330
331
332
333
    i_dummy = sizeof( struct sockaddr );
    recvfrom( i_fd, psz_mess, MESSAGE_LENGTH, 0,
              (struct sockaddr *)(&sa_client), &i_dummy);
    psz_mess[ MESSAGE_LENGTH - 1 ] = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
334

Sam Hocevar's avatar
   
Sam Hocevar committed
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
    if( !strncasecmp( psz_mess, "E: ", 3 ) )
    {
        intf_ErrMsg( "network error: vlcs said '%s'", psz_mess + 3 );
        close( i_fd );
        return -1;
    }
    else if( !strncasecmp( psz_mess, "I: ", 3 ) )
    {
        intf_WarnMsg( 2, "network info: vlcs said '%s'", psz_mess + 3 );
    }
    else /* We got something to play ! FIXME: not very nice */
    {
#   define p_item \
        (&p_main->p_playlist->p_item[ p_main->p_playlist->i_index + 1])
        vlc_mutex_lock( &p_main->p_playlist->change_lock );
350
351
352
353
        if( p_item )
        {
            free( p_item->psz_name );
            p_item->psz_name = strdup( psz_mess );
Sam Hocevar's avatar
   
Sam Hocevar committed
354
355
            /* Unlock _afterwards_ */
            vlc_mutex_unlock( &p_main->p_playlist->change_lock );
356
357
358
        }
        else
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
359
360
            /* Unlock _before_ */
            vlc_mutex_unlock( &p_main->p_playlist->change_lock );
361
362
            intf_PlaylistAdd( p_main->p_playlist, 0, psz_mess );
        }
Henri Fallon's avatar
   
Henri Fallon committed
363
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
364

Sam Hocevar's avatar
   
Sam Hocevar committed
365
366
    /* Close the socket and return nicely */
    close( i_fd );
Henri Fallon's avatar
   
Henri Fallon committed
367

Sam Hocevar's avatar
   
Sam Hocevar committed
368
    return 0;
Marc Ariberti's avatar
Marc Ariberti committed
369

Sam Hocevar's avatar
   
Sam Hocevar committed
370
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
371
    intf_ErrMsg( "network error: channels not supported on this platform" );
Sam Hocevar's avatar
   
Sam Hocevar committed
372
    return -1; 
Sam Hocevar's avatar
   
Sam Hocevar committed
373
374

#endif
Henri Fallon's avatar
   
Henri Fallon committed
375
}
Sam Hocevar's avatar
   
Sam Hocevar committed
376

Sam Hocevar's avatar
   
Sam Hocevar committed
377
378
379
380
381
/* Following functions are local */

/*****************************************************************************
 * GetMacAddress: extract the MAC Address
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
382
static int GetMacAddress( int i_fd, char *psz_mac )
Sam Hocevar's avatar
   
Sam Hocevar committed
383
384
385
386
{
#if defined( SYS_LINUX )
    struct ifreq interface;
    int i_ret;
gbazin's avatar
   
gbazin committed
387
    char *psz_interface;
Sam Hocevar's avatar
   
Sam Hocevar committed
388
389
390
391
392

    /*
     * Looking for information about the eth0 interface
     */
    interface.ifr_addr.sa_family = AF_INET;
gbazin's avatar
   
gbazin committed
393
394
395
396
397
398
399
400
    if( !(psz_interface = config_GetPszVariable( INPUT_IFACE_VAR )) )
    {
        intf_ErrMsg( "network error: configuration variable %s empty",
                     INPUT_IFACE_VAR );
        return -1;
    }
    strcpy( interface.ifr_name, psz_interface );
    free( psz_interface );
Sam Hocevar's avatar
   
Sam Hocevar committed
401

Sam Hocevar's avatar
   
Sam Hocevar committed
402
    i_ret = ioctl( i_fd, SIOCGIFHWADDR, &interface );
Sam Hocevar's avatar
   
Sam Hocevar committed
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439

    if( i_ret )
    {
        intf_ErrMsg( "network error: ioctl SIOCGIFHWADDR failed" );
        return( i_ret );
    }

    sprintf( psz_mac, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
                      interface.ifr_hwaddr.sa_data[0] & 0xff,
                      interface.ifr_hwaddr.sa_data[1] & 0xff,
                      interface.ifr_hwaddr.sa_data[2] & 0xff,
                      interface.ifr_hwaddr.sa_data[3] & 0xff,
                      interface.ifr_hwaddr.sa_data[4] & 0xff,
                      interface.ifr_hwaddr.sa_data[5] & 0xff );

    return( 0 );

#elif defined( WIN32 )
    int i, i_ret = -1;

    /* Get adapter list - support for more than one adapter */
    LANA_ENUM AdapterList;
    NCB       Ncb;

    intf_WarnMsg( 2, "network: looking for MAC address" );

    memset( &Ncb, 0, sizeof( NCB ) );
    Ncb.ncb_command = NCBENUM;
    Ncb.ncb_buffer = (unsigned char *)&AdapterList;
    Ncb.ncb_length = sizeof( AdapterList );
    Netbios( &Ncb );

    /* Get all of the local ethernet addresses */
    for ( i = 0; i < AdapterList.length ; ++i )
    {
        if ( GetAdapterInfo ( AdapterList.lana[ i ], psz_mac ) == 0 )
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
440
            i_ret = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
441
442
443
444
445
        }
    }

    return( i_ret );

Sam Hocevar's avatar
   
Sam Hocevar committed
446
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
    return( -1);

#endif
}

#ifdef WIN32
/*****************************************************************************
 * GetAdapterInfo : gets some informations about the interface using NETBIOS
 *****************************************************************************/
static int GetAdapterInfo( int i_adapter, char *psz_string )
{
    struct ASTAT
    {
        ADAPTER_STATUS adapt;
        NAME_BUFFER    psz_name[30];
    } Adapter;

    /* Reset the LAN adapter so that we can begin querying it */
    NCB Ncb;
    memset( &Ncb, 0, sizeof ( Ncb ) );
    Ncb.ncb_command  = NCBRESET;
    Ncb.ncb_lana_num = i_adapter;

    if( Netbios( &Ncb ) != NRC_GOODRET )
    {
        intf_ErrMsg( "network error: reset returned %i", Ncb.ncb_retcode );
        return -1;
    }

    /* Prepare to get the adapter status block */
    memset( &Ncb, 0, sizeof( Ncb ) ) ;     /* Initialization */
    Ncb.ncb_command = NCBASTAT;
    Ncb.ncb_lana_num = i_adapter;

    strcpy( (char *)Ncb.ncb_callname, "*" );

    memset( &Adapter, 0, sizeof ( Adapter ) );
    Ncb.ncb_buffer = ( unsigned char * ) &Adapter;
    Ncb.ncb_length = sizeof ( Adapter );

    /* Get the adapter's info and, if this works, return it in standard,
     * colon-delimited form. */
    if ( Netbios( &Ncb ) == 0 )
    {
        sprintf ( psz_string, "%02X:%02X:%02X:%02X:%02X:%02X",
                (int) ( Adapter.adapt.adapter_address[0] ),
                (int) ( Adapter.adapt.adapter_address[1] ),
                (int) ( Adapter.adapt.adapter_address[2] ),
                (int) ( Adapter.adapt.adapter_address[3] ),
                (int) ( Adapter.adapt.adapter_address[4] ),
                (int) ( Adapter.adapt.adapter_address[5] ) );

Sam Hocevar's avatar
   
Sam Hocevar committed
499
        intf_WarnMsg( 2, "network: found MAC address %s", psz_string );
Sam Hocevar's avatar
   
Sam Hocevar committed
500
501
502
503
504
505
506
507
508
509
510

        return 0;
    }
    else
    {
        intf_ErrMsg( "network error: ASTAT returned %i", Ncb.ncb_retcode );
        return -1;
    }
}
#endif /* WIN32 */