netutils.c 17.6 KB
Newer Older
1
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
2
 * netutils.c: various network functions
3
 *****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
4
 * Copyright (C) 1999, 2000, 2001 VideoLAN
Sam Hocevar's avatar
   
Sam Hocevar committed
5
 * $Id: netutils.c,v 1.42 2001/11/12 20:16:33 sam 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
13
14
15
 *
 * 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
16
 *
17
18
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
21
 *
22
23
24
 * 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.
25
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
26

27
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
28
 * Preamble
29
 *****************************************************************************/
30
31
#include "defs.h"

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
38
39
#ifdef STRNCASECMP_IN_STRINGS_H
#   include <strings.h>
#endif

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

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

Sam Hocevar's avatar
   
Sam Hocevar committed
50
#if !defined( WIN32 )
Sam Hocevar's avatar
   
Sam Hocevar committed
51
#include <netdb.h>                                        /* gethostbyname() */
52
53
#include <netinet/in.h>                               /* BSD: struct in_addr */
#include <sys/socket.h>                              /* BSD: struct sockaddr */
Sam Hocevar's avatar
   
Sam Hocevar committed
54
55
#endif

56
#ifdef HAVE_ARPA_INET_H
57
58
59
#include <arpa/inet.h>                           /* inet_ntoa(), inet_aton() */
#endif

Henri Fallon's avatar
   
Henri Fallon committed
60
61
62
63
#ifdef SYS_LINUX
#include <sys/ioctl.h>                                            /* ioctl() */
#endif

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

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

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

#include "config.h"
#include "common.h"
#include "mtime.h"
Henri Fallon's avatar
   
Henri Fallon committed
80
#include "threads.h"
Henri Fallon's avatar
   
Henri Fallon committed
81
#include "main.h"
Michel Kaempf's avatar
Michel Kaempf committed
82
83

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

Sam Hocevar's avatar
   
Sam Hocevar committed
86
#include "netutils.h"
Henri Fallon's avatar
   
Henri Fallon committed
87

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

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

Henri Fallon's avatar
   
Henri Fallon committed
110
111
/*****************************************************************************
 * network_BuildLocalAddr : fill a sockaddr_in structure for local binding
112
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
113
int network_BuildLocalAddr( struct sockaddr_in * p_socket, int i_port,
Henri Fallon's avatar
   
Henri Fallon committed
114
                            char * psz_broadcast )
Michel Kaempf's avatar
Michel Kaempf committed
115
{
Tony Castley's avatar
Tony Castley committed
116

Henri Fallon's avatar
   
Henri Fallon committed
117
118
    char                psz_hostname[INPUT_MAX_SOURCE_LENGTH];
    struct hostent    * p_hostent;
Sam Hocevar's avatar
   
Sam Hocevar committed
119

Tony Castley's avatar
Tony Castley committed
120
121
122
123
124
#if defined( SYS_BEOS )
    intf_ErrMsg( "error: channel changing is not yet supported under BeOS" );
    return( 1 );
#endif

Henri Fallon's avatar
   
Henri Fallon committed
125
126
    /* Reset struct */
    memset( p_socket, 0, sizeof( struct sockaddr_in ) );
Sam Hocevar's avatar
   
Sam Hocevar committed
127
    p_socket->sin_family = AF_INET;                                /* family */
Henri Fallon's avatar
   
Henri Fallon committed
128
    p_socket->sin_port = htons( i_port );
Henri Fallon's avatar
   
Henri Fallon committed
129
    if( psz_broadcast == NULL )
Henri Fallon's avatar
   
Henri Fallon committed
130
131
132
133
134
135
136
137
    {
        /* Try to get our own IP */
        if( gethostname( psz_hostname, sizeof(psz_hostname) ) )
        {
            intf_ErrMsg( "BuildLocalAddr : unable to resolve local name : %s",
                         strerror( errno ) );
            return( -1 );
        }
Michel Kaempf's avatar
Michel Kaempf committed
138

Henri Fallon's avatar
   
Henri Fallon committed
139
140
    }
    else
Sam Hocevar's avatar
   
Sam Hocevar committed
141
142
    {
        /* I didn't manage to make INADDR_ANYT work, even with setsockopt
Henri Fallon's avatar
   
Henri Fallon committed
143
144
145
         * so, as it's kludgy to try and determine the broadcast addr
         * it is passed as an argument in the command line */
        strncpy( psz_hostname, psz_broadcast, INPUT_MAX_SOURCE_LENGTH );
146
    }
Henri Fallon's avatar
   
Henri Fallon committed
147

148
149
    /* Try to convert address directly from in_addr - this will work if
     * psz_in_addr is dotted decimal. */
Henri Fallon's avatar
   
Henri Fallon committed
150
151
#ifdef HAVE_ARPA_INET_H
    if( !inet_aton( psz_hostname, &p_socket->sin_addr) )
152
#else
Henri Fallon's avatar
   
Henri Fallon committed
153
    if( (p_socket->sin_addr.s_addr = inet_addr( psz_hostname )) == -1 )
154
#endif
Michel Kaempf's avatar
Michel Kaempf committed
155
    {
Henri Fallon's avatar
   
Henri Fallon committed
156
157
        /* We have a fqdn, try to find its address */
        if ( (p_hostent = gethostbyname( psz_hostname )) == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
158
        {
Henri Fallon's avatar
   
Henri Fallon committed
159
            intf_ErrMsg( "BuildLocalAddr: unknown host %s", psz_hostname );
160
            return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
161
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
162

Michel Kaempf's avatar
Michel Kaempf committed
163
        /* Copy the first address of the host in the socket address */
Sam Hocevar's avatar
   
Sam Hocevar committed
164
        memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0],
Henri Fallon's avatar
   
Henri Fallon committed
165
                 p_hostent->h_length );
Michel Kaempf's avatar
Michel Kaempf committed
166
    }
167
    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
168
169
}

170
/*****************************************************************************
Henri Fallon's avatar
   
Henri Fallon committed
171
 * network_BuildRemoteAddr : fill a sockaddr_in structure for remote host
172
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
173
int network_BuildRemoteAddr( struct sockaddr_in * p_socket, char * psz_server )
Michel Kaempf's avatar
Michel Kaempf committed
174
{
Tony Castley's avatar
Tony Castley committed
175

Henri Fallon's avatar
   
Henri Fallon committed
176
    struct hostent            * p_hostent;
Sam Hocevar's avatar
   
Sam Hocevar committed
177

Tony Castley's avatar
Tony Castley committed
178
179
180
181
182
#if defined( SYS_BEOS )
    intf_ErrMsg( "error: channel changing is not yet supported under BeOS" );
    return( 1 );
#endif

Henri Fallon's avatar
   
Henri Fallon committed
183
184
    /* Reset structure */
    memset( p_socket, 0, sizeof( struct sockaddr_in ) );
Sam Hocevar's avatar
   
Sam Hocevar committed
185
186
    p_socket->sin_family = AF_INET;                                /* family */
    p_socket->sin_port = htons( 0 );               /* This is for remote end */
Sam Hocevar's avatar
   
Sam Hocevar committed
187

Henri Fallon's avatar
   
Henri Fallon committed
188
189
     /* Try to convert address directly from in_addr - this will work if
      * psz_in_addr is dotted decimal. */
Michel Kaempf's avatar
Michel Kaempf committed
190

Henri Fallon's avatar
   
Henri Fallon committed
191
192
#ifdef HAVE_ARPA_INET_H
    if( !inet_aton( psz_server, &p_socket->sin_addr) )
Benoit Steiner's avatar
Benoit Steiner committed
193
#else
Henri Fallon's avatar
   
Henri Fallon committed
194
    if( (p_socket->sin_addr.s_addr = inet_addr( psz_server )) == -1 )
195
#endif
Michel Kaempf's avatar
Michel Kaempf committed
196
    {
Henri Fallon's avatar
   
Henri Fallon committed
197
198
        /* We have a fqdn, try to find its address */
        if ( (p_hostent = gethostbyname(psz_server)) == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
199
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
200
            intf_ErrMsg( "BuildRemoteAddr: unknown host %s",
Henri Fallon's avatar
   
Henri Fallon committed
201
202
                         psz_server );
            return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
203
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
204

Henri Fallon's avatar
   
Henri Fallon committed
205
        /* Copy the first address of the host in the socket address */
Sam Hocevar's avatar
   
Sam Hocevar committed
206
        memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0],
Henri Fallon's avatar
   
Henri Fallon committed
207
                 p_hostent->h_length );
Michel Kaempf's avatar
Michel Kaempf committed
208
    }
Henri Fallon's avatar
   
Henri Fallon committed
209
    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
210
}
Sam Hocevar's avatar
   
Sam Hocevar committed
211

Henri Fallon's avatar
   
Henri Fallon committed
212
213
214
215
/*****************************************************************************
 * 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
216
 * once before any input thread is created or any call to other
Henri Fallon's avatar
   
Henri Fallon committed
217
218
219
220
 * input_Channel*() function is attempted.
 *****************************************************************************/
int network_ChannelCreate( void )
{
Sam Hocevar's avatar
   
Sam Hocevar committed
221
#if defined( SYS_LINUX ) || defined( WIN32 )
Sam Hocevar's avatar
   
Sam Hocevar committed
222

Henri Fallon's avatar
   
Henri Fallon committed
223
224
225
226
    /* Allocate structure */
    p_main->p_channel = malloc( sizeof( input_channel_t ) );
    if( p_main->p_channel == NULL )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
227
        intf_ErrMsg( "network error: could not create channel bank" );
Henri Fallon's avatar
   
Henri Fallon committed
228
229
230
231
        return( -1 );
    }

    /* Initialize structure */
Sam Hocevar's avatar
   
Sam Hocevar committed
232
    p_main->p_channel->i_channel   = 0;
Henri Fallon's avatar
   
Henri Fallon committed
233
234
    p_main->p_channel->last_change = 0;

Sam Hocevar's avatar
   
Sam Hocevar committed
235
    intf_WarnMsg( 2, "network: channels initialized" );
Henri Fallon's avatar
   
Henri Fallon committed
236
    return( 0 );
Sam Hocevar's avatar
   
Sam Hocevar committed
237

Henri Fallon's avatar
   
Henri Fallon committed
238
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
239
    intf_ErrMsg( "network error : channels not supported on this platform" );
Sam Hocevar's avatar
   
Sam Hocevar committed
240
    return( 1 );
Sam Hocevar's avatar
   
Sam Hocevar committed
241
242

#endif
Henri Fallon's avatar
   
Henri Fallon committed
243
244
245
246
247
}

/*****************************************************************************
 * network_ChannelJoin: join a channel
 *****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
248
249
250
251
 * 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
252
 * is effective. Note that once a channel is no more used, its interface
Henri Fallon's avatar
   
Henri Fallon committed
253
254
255
 * should be unlocked using input_ChannelLeave().
 * Non 0 will be returned in case of error.
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
256
int network_ChannelJoin( int i_channel )
Henri Fallon's avatar
   
Henri Fallon committed
257
{
Sam Hocevar's avatar
   
Sam Hocevar committed
258
259
260
#if defined( SYS_LINUX ) || defined( WIN32 )

#define VLCS_VERSION 12
Sam Hocevar's avatar
   
Sam Hocevar committed
261
#define MESSAGE_LENGTH 256
Sam Hocevar's avatar
   
Sam Hocevar committed
262
263
264
265
266
267
268
269
270

    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
271

272
273
    if( !main_GetIntVariable( INPUT_NETWORK_CHANNEL_VAR,
                              INPUT_NETWORK_CHANNEL_DEFAULT  ) )
Henri Fallon's avatar
   
Henri Fallon committed
274
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
275
276
        intf_ErrMsg( "network: channels disabled, to enable them, use the"
                     "--channels option" );
Sam Hocevar's avatar
   
Sam Hocevar committed
277
        return -1;
Henri Fallon's avatar
   
Henri Fallon committed
278
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
279

Henri Fallon's avatar
   
Henri Fallon committed
280
281
282
    /* If last change is too recent, wait a while */
    if( mdate() - p_main->p_channel->last_change < INPUT_CHANNEL_CHANGE_DELAY )
    {
283
        intf_WarnMsg( 2, "network: waiting before changing channel" );
Sam Hocevar's avatar
   
Sam Hocevar committed
284
        /* XXX Isn't this completely brain-damaged ??? -- Sam */
Henri Fallon's avatar
   
Henri Fallon committed
285
286
        mwait( p_main->p_channel->last_change + INPUT_CHANNEL_CHANGE_DELAY );
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
287

Sam Hocevar's avatar
   
Sam Hocevar committed
288
289
    /* Initializing the socket */
    i_fd = socket( AF_INET, SOCK_DGRAM, 0 );
Henri Fallon's avatar
   
Henri Fallon committed
290

Sam Hocevar's avatar
   
Sam Hocevar committed
291
292
293
294
295
    /* 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
296

Sam Hocevar's avatar
   
Sam Hocevar committed
297
    intf_WarnMsg( 6, "network: vlcs '%s', port %d", psz_vlcs, i_port );
298

Sam Hocevar's avatar
   
Sam Hocevar committed
299
    memset( &sa_client, 0x00, sizeof(struct sockaddr_in) );
Sam Hocevar's avatar
   
Sam Hocevar committed
300
    memset( &sa_server, 0x00, sizeof(struct sockaddr_in) );
Sam Hocevar's avatar
   
Sam Hocevar committed
301
302
303
304
305
    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
306
#ifdef HAVE_ARPA_INET_H
Sam Hocevar's avatar
   
Sam Hocevar committed
307
    inet_aton( psz_vlcs, &sa_server.sin_addr );
Sam Hocevar's avatar
   
Sam Hocevar committed
308
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
309
    sa_server.sin_addr.s_addr = inet_addr( psz_vlcs );
Sam Hocevar's avatar
   
Sam Hocevar committed
310
#endif
Marc Ariberti's avatar
Marc Ariberti committed
311

Sam Hocevar's avatar
   
Sam Hocevar committed
312
313
314
315
316
317
318
319
320
321
322
    /* Bind the socket */
    i_dummy = bind( i_fd, (struct sockaddr *)(&sa_client),
                          sizeof(struct sockaddr) );
    if ( i_dummy )
    {
        intf_ErrMsg( "network: unable to bind vlcs socket: %i", i_dummy );
        return -1;
    }

    /* Look for the interface MAC address */
    if( GetMacAddress( i_fd, psz_mac ) )
Henri Fallon's avatar
   
Henri Fallon committed
323
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
324
        intf_ErrMsg( "network error: failed getting MAC address" );
Sam Hocevar's avatar
   
Sam Hocevar committed
325
        return -1;
Marc Ariberti's avatar
Marc Ariberti committed
326
    }
Henri Fallon's avatar
   
Henri Fallon committed
327

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

Sam Hocevar's avatar
   
Sam Hocevar committed
330
331
332
333
    /* Build the message */
    sprintf( psz_mess, "%d %u %lu %s \n", i_channel, VLCS_VERSION,
                       (unsigned long)(mdate() / (unsigned long long)1000000),
                       psz_mac );
Sam Hocevar's avatar
   
Sam Hocevar committed
334

Sam Hocevar's avatar
   
Sam Hocevar committed
335
336
337
    /* 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
338

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

Sam Hocevar's avatar
   
Sam Hocevar committed
341
342
343
    /* 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
344

Sam Hocevar's avatar
   
Sam Hocevar committed
345
346
347
    /* Wait 5 sec for an answer from the server */
    delay.tv_sec = 5;
    delay.tv_usec = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
348
    FD_ZERO( &fds );
Sam Hocevar's avatar
   
Sam Hocevar committed
349
350
    FD_SET( i_fd, &fds );
    i_dummy = select( i_fd + 1, &fds, NULL, NULL, &delay );
Sam Hocevar's avatar
   
Sam Hocevar committed
351

Sam Hocevar's avatar
   
Sam Hocevar committed
352
    switch( i_dummy )
Henri Fallon's avatar
   
Henri Fallon committed
353
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
354
355
356
357
358
359
360
361
362
363
364
365
        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
366

Sam Hocevar's avatar
   
Sam Hocevar committed
367
368
369
370
    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
371

Sam Hocevar's avatar
   
Sam Hocevar committed
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
    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 );
        free( p_item->psz_name );
        p_item->psz_name = strdup( psz_mess );
        vlc_mutex_unlock( &p_main->p_playlist->change_lock );
Henri Fallon's avatar
   
Henri Fallon committed
390
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
391

Sam Hocevar's avatar
   
Sam Hocevar committed
392
393
    /* Close the socket and return nicely */
    close( i_fd );
Henri Fallon's avatar
   
Henri Fallon committed
394

Sam Hocevar's avatar
   
Sam Hocevar committed
395
    return 0;
Marc Ariberti's avatar
Marc Ariberti committed
396

Sam Hocevar's avatar
   
Sam Hocevar committed
397
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
398
399
    intf_ErrMsg( "network error: channels not supported on this platform" );
    return NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
400
401

#endif
Henri Fallon's avatar
   
Henri Fallon committed
402
}
Sam Hocevar's avatar
   
Sam Hocevar committed
403

Sam Hocevar's avatar
   
Sam Hocevar committed
404
405
406
407
408
/* Following functions are local */

/*****************************************************************************
 * GetMacAddress: extract the MAC Address
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
409
static int GetMacAddress( int i_fd, char *psz_mac )
Sam Hocevar's avatar
   
Sam Hocevar committed
410
411
412
413
414
415
416
417
418
{
#if defined( SYS_LINUX )
    struct ifreq interface;
    int i_ret;

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

Sam Hocevar's avatar
   
Sam Hocevar committed
422
    i_ret = ioctl( i_fd, SIOCGIFHWADDR, &interface );
Sam Hocevar's avatar
   
Sam Hocevar committed
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459

    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
460
            i_ret = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
461
462
463
464
465
        }
    }

    return( i_ret );

Sam Hocevar's avatar
   
Sam Hocevar committed
466
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
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
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
    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
519
        intf_WarnMsg( 2, "network: found MAC address %s", psz_string );
Sam Hocevar's avatar
   
Sam Hocevar committed
520
521
522
523
524
525
526
527
528
529
530

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