netutils.c 16.5 KB
Newer Older
1
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
2
 * netutils.c: various network functions
3
 *****************************************************************************
4
5
 * Copyright (C) 1999-2001 VideoLAN
 * $Id: netutils.c,v 1.52 2001/11/28 15:08:06 massiot 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 "defs.h"

34
35
#include <stdlib.h>                             /* free(), realloc(), atoi() */
#include <errno.h>                                                /* errno() */
Sam Hocevar's avatar
   
Sam Hocevar committed
36
#include <string.h>                                              /* memset() */
Sam Hocevar's avatar
   
Sam Hocevar committed
37

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
54
55
56
57
58
59
60
#ifdef WIN32
#   include <winsock2.h>
#elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
#   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
70
71
#include <stdio.h>
#endif

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

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

#include "config.h"
#include "common.h"
#include "mtime.h"
83
#include "intf_msg.h"
Henri Fallon's avatar
   
Henri Fallon committed
84
#include "threads.h"
Henri Fallon's avatar
   
Henri Fallon committed
85
#include "main.h"
Michel Kaempf's avatar
Michel Kaempf committed
86

Sam Hocevar's avatar
   
Sam Hocevar committed
87
#include "intf_playlist.h"
Michel Kaempf's avatar
Michel Kaempf committed
88

Sam Hocevar's avatar
   
Sam Hocevar committed
89
#include "netutils.h"
Henri Fallon's avatar
   
Henri Fallon committed
90

91
/*****************************************************************************
Henri Fallon's avatar
   
Henri Fallon committed
92
93
94
95
96
97
98
99
100
 * 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
101
    int         i_channel;                         /* current channel number */
Henri Fallon's avatar
   
Henri Fallon committed
102
103
104
    mtime_t     last_change;                             /* last change date */
} input_channel_t;

Xavier Marchesini's avatar
Xavier Marchesini committed
105
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
106
107
 * Local prototypes
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
108
static int GetMacAddress   ( int i_fd, char *psz_mac );
Sam Hocevar's avatar
   
Sam Hocevar committed
109
110
#ifdef WIN32
static int GetAdapterInfo  ( int i_adapter, char *psz_string );
Xavier Marchesini's avatar
Xavier Marchesini committed
111
112
#endif

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

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

136
137
        /* Try to convert address directly from in_addr - this will work if
         * psz_broadcast is dotted decimal. */
Henri Fallon's avatar
   
Henri Fallon committed
138
#ifdef HAVE_ARPA_INET_H
139
        if( !inet_aton( psz_address, &p_socket->sin_addr) )
140
#else
141
        if( (p_socket->sin_addr.s_addr = inet_addr( psz_address )) == -1 )
142
#endif
Michel Kaempf's avatar
Michel Kaempf committed
143
        {
144
            /* We have a fqdn, try to find its address */
145
            if ( (p_hostent = gethostbyname( psz_address )) == NULL )
146
            {
147
                intf_ErrMsg( "BuildLocalAddr: unknown host %s", psz_address );
148
149
150
151
152
153
                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
154
155
        }
    }
156
    return( 0 );
Sam Hocevar's avatar
   
Sam Hocevar committed
157
#endif
Michel Kaempf's avatar
Michel Kaempf committed
158
159
}

Henri Fallon's avatar
   
Henri Fallon committed
160
161
162
163
/*****************************************************************************
 * 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
164
 * once before any input thread is created or any call to other
Henri Fallon's avatar
   
Henri Fallon committed
165
166
167
168
 * input_Channel*() function is attempted.
 *****************************************************************************/
int network_ChannelCreate( void )
{
Sam Hocevar's avatar
   
Sam Hocevar committed
169
#if defined( SYS_LINUX ) || defined( WIN32 )
Sam Hocevar's avatar
   
Sam Hocevar committed
170

Henri Fallon's avatar
   
Henri Fallon committed
171
172
173
174
    /* Allocate structure */
    p_main->p_channel = malloc( sizeof( input_channel_t ) );
    if( p_main->p_channel == NULL )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
175
        intf_ErrMsg( "network error: could not create channel bank" );
Henri Fallon's avatar
   
Henri Fallon committed
176
177
178
179
        return( -1 );
    }

    /* Initialize structure */
Sam Hocevar's avatar
   
Sam Hocevar committed
180
    p_main->p_channel->i_channel   = 0;
Henri Fallon's avatar
   
Henri Fallon committed
181
182
    p_main->p_channel->last_change = 0;

Sam Hocevar's avatar
   
Sam Hocevar committed
183
    intf_WarnMsg( 2, "network: channels initialized" );
Henri Fallon's avatar
   
Henri Fallon committed
184
    return( 0 );
Sam Hocevar's avatar
   
Sam Hocevar committed
185

Henri Fallon's avatar
   
Henri Fallon committed
186
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
187
    intf_ErrMsg( "network error : channels not supported on this platform" );
Sam Hocevar's avatar
   
Sam Hocevar committed
188
    return( 1 );
Sam Hocevar's avatar
   
Sam Hocevar committed
189
190

#endif
Henri Fallon's avatar
   
Henri Fallon committed
191
192
193
194
195
}

/*****************************************************************************
 * network_ChannelJoin: join a channel
 *****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
196
197
198
199
 * 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
200
 * is effective. Note that once a channel is no more used, its interface
Henri Fallon's avatar
   
Henri Fallon committed
201
202
203
 * should be unlocked using input_ChannelLeave().
 * Non 0 will be returned in case of error.
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
204
int network_ChannelJoin( int i_channel )
Henri Fallon's avatar
   
Henri Fallon committed
205
{
Sam Hocevar's avatar
   
Sam Hocevar committed
206
207
#if defined( SYS_LINUX ) || defined( WIN32 )

208
#define VLCS_VERSION 13
Sam Hocevar's avatar
   
Sam Hocevar committed
209
#define MESSAGE_LENGTH 256
Sam Hocevar's avatar
   
Sam Hocevar committed
210
211
212
213
214
215
216
217
218

    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
219

220
221
    if( !main_GetIntVariable( INPUT_NETWORK_CHANNEL_VAR,
                              INPUT_NETWORK_CHANNEL_DEFAULT  ) )
Henri Fallon's avatar
   
Henri Fallon committed
222
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
223
224
        intf_ErrMsg( "network: channels disabled, to enable them, use the"
                     "--channels option" );
Sam Hocevar's avatar
   
Sam Hocevar committed
225
        return -1;
Henri Fallon's avatar
   
Henri Fallon committed
226
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
227

Henri Fallon's avatar
   
Henri Fallon committed
228
229
230
    /* If last change is too recent, wait a while */
    if( mdate() - p_main->p_channel->last_change < INPUT_CHANNEL_CHANGE_DELAY )
    {
231
        intf_WarnMsg( 2, "network: waiting before changing channel" );
Sam Hocevar's avatar
   
Sam Hocevar committed
232
        /* XXX Isn't this completely brain-damaged ??? -- Sam */
Henri Fallon's avatar
   
Henri Fallon committed
233
234
        mwait( p_main->p_channel->last_change + INPUT_CHANNEL_CHANGE_DELAY );
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
235

Sam Hocevar's avatar
   
Sam Hocevar committed
236
237
    /* Initializing the socket */
    i_fd = socket( AF_INET, SOCK_DGRAM, 0 );
Sam Hocevar's avatar
   
Sam Hocevar committed
238
239
240
241
242
243
    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
244

Sam Hocevar's avatar
   
Sam Hocevar committed
245
246
247
248
249
250
251
252
253
254
    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
255
256
257
258
259
    /* Getting information about the channel server */
    psz_vlcs = main_GetPszVariable( INPUT_CHANNEL_SERVER_VAR,
                                    INPUT_CHANNEL_SERVER_DEFAULT );
    i_port = main_GetIntVariable( INPUT_CHANNEL_PORT_VAR,
                                  INPUT_CHANNEL_PORT_DEFAULT );
Henri Fallon's avatar
   
Henri Fallon committed
260

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

Sam Hocevar's avatar
   
Sam Hocevar committed
264
    memset( &sa_client, 0x00, sizeof(struct sockaddr_in) );
Sam Hocevar's avatar
   
Sam Hocevar committed
265
    memset( &sa_server, 0x00, sizeof(struct sockaddr_in) );
Sam Hocevar's avatar
   
Sam Hocevar committed
266
267
268
269
270
    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
271
#ifdef HAVE_ARPA_INET_H
Sam Hocevar's avatar
   
Sam Hocevar committed
272
    inet_aton( psz_vlcs, &sa_server.sin_addr );
Sam Hocevar's avatar
   
Sam Hocevar committed
273
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
274
    sa_server.sin_addr.s_addr = inet_addr( psz_vlcs );
Sam Hocevar's avatar
   
Sam Hocevar committed
275
#endif
Marc Ariberti's avatar
Marc Ariberti committed
276

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

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

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

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

Sam Hocevar's avatar
   
Sam Hocevar committed
301
302
303
    /* 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
304

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

Sam Hocevar's avatar
   
Sam Hocevar committed
307
308
309
    /* 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
310

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

Sam Hocevar's avatar
   
Sam Hocevar committed
317
    switch( select( i_fd + 1, &fds, NULL, NULL, &delay ) )
Henri Fallon's avatar
   
Henri Fallon committed
318
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
319
320
321
322
323
324
325
326
327
328
329
330
        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
331

Sam Hocevar's avatar
   
Sam Hocevar committed
332
333
334
335
    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
336

Sam Hocevar's avatar
   
Sam Hocevar committed
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
    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 );
352
353
354
355
        if( p_item )
        {
            free( p_item->psz_name );
            p_item->psz_name = strdup( psz_mess );
Sam Hocevar's avatar
   
Sam Hocevar committed
356
357
            /* Unlock _afterwards_ */
            vlc_mutex_unlock( &p_main->p_playlist->change_lock );
358
359
360
        }
        else
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
361
362
            /* Unlock _before_ */
            vlc_mutex_unlock( &p_main->p_playlist->change_lock );
363
364
            intf_PlaylistAdd( p_main->p_playlist, 0, psz_mess );
        }
Henri Fallon's avatar
   
Henri Fallon committed
365
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
366

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

Sam Hocevar's avatar
   
Sam Hocevar committed
370
    return 0;
Marc Ariberti's avatar
Marc Ariberti committed
371

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

#endif
Henri Fallon's avatar
   
Henri Fallon committed
377
}
Sam Hocevar's avatar
   
Sam Hocevar committed
378

Sam Hocevar's avatar
   
Sam Hocevar committed
379
380
381
382
383
/* Following functions are local */

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

    /*
     * Looking for information about the eth0 interface
     */
    interface.ifr_addr.sa_family = AF_INET;
394
395
    strcpy( interface.ifr_name, 
            main_GetPszVariable( INPUT_IFACE_VAR, INPUT_IFACE_DEFAULT ) );
Sam Hocevar's avatar
   
Sam Hocevar committed
396

Sam Hocevar's avatar
   
Sam Hocevar committed
397
    i_ret = ioctl( i_fd, SIOCGIFHWADDR, &interface );
Sam Hocevar's avatar
   
Sam Hocevar committed
398
399
400
401
402
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

    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
435
            i_ret = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
436
437
438
439
440
        }
    }

    return( i_ret );

Sam Hocevar's avatar
   
Sam Hocevar committed
441
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
442
443
444
445
446
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
    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
494
        intf_WarnMsg( 2, "network: found MAC address %s", psz_string );
Sam Hocevar's avatar
   
Sam Hocevar committed
495
496
497
498
499
500
501
502
503
504
505

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