~ubuntu-branches/ubuntu/maverick/vlc/maverick

« back to all changes in this revision

Viewing changes to modules/control/telnet.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2008-09-17 21:56:14 UTC
  • mfrom: (1.1.17 upstream)
  • Revision ID: james.westby@ubuntu.com-20080917215614-tj0vx8xzd57e52t8
Tags: 0.9.2-1ubuntu1
* New Upstream Release, exception granted by
    - dktrkranz, norsetto, Hobbsee (via irc). LP: #270404

Changes done in ubuntu:

* add libxul-dev to build-depends
* make sure that vlc is build against libxul in configure. This doesn't
  change anything in the package, but makes it more robust if building
  in an 'unclean' chroot or when modifying the package.
* debian/control: make Vcs-* fields point to the motumedia branch
* add libx264-dev and libass-dev to build-depends
  LP: #210354, #199870
* actually enable libass support by passing --enable-libass to configure
* enable libdca: add libdca-dev to build depends and --enable-libdca
* install the x264 plugin.

Changes already in the pkg-multimedia branch in debian:

* don't install usr/share/vlc/mozilla in debian/mozilla-plugin-vlc.install  
* new upstream .desktop file now registers flash video mimetype LP: #261567
* add Xb-Npp-Applications to mozilla-plugin-vlc
* remove duplicate entries in debian/vlc-nox.install

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * telnet.c: VLM interface plugin
3
3
 *****************************************************************************
4
4
 * Copyright (C) 2000-2006 the VideoLAN team
5
 
 * $Id: 2c01c2c9b10169fac082556175b43e795096e59f $
 
5
 * $Id: cffbdd849cf17b9b26effb8772e972acfd8fd3b2 $
6
6
 *
7
7
 * Authors: Simon Latapie <garf@videolan.org>
8
8
 *          Laurent Aimar <fenrir@videolan.org>
25
25
/*****************************************************************************
26
26
 * Preamble
27
27
 *****************************************************************************/
28
 
#include <stdlib.h>                                      /* malloc(), free() */
29
 
 
30
 
#include <vlc/vlc.h>
31
 
#include <vlc/intf.h>
32
 
 
33
 
#include <vlc/input.h>
34
 
 
 
28
 
 
29
#ifdef HAVE_CONFIG_H
 
30
# include "config.h"
 
31
#endif
 
32
 
 
33
#include <vlc_common.h>
 
34
#include <vlc_plugin.h>
 
35
#include <vlc_interface.h>
 
36
#include <vlc_input.h>
 
37
 
 
38
#include <stdbool.h>
35
39
#include <sys/stat.h>
36
40
 
37
41
#include <errno.h>
44
48
#ifdef HAVE_UNISTD_H
45
49
#   include <unistd.h>
46
50
#endif
47
 
 
48
 
#include "network.h"
49
 
#include "vlc_url.h"
50
 
 
51
 
#include "vlc_vlm.h"
 
51
#ifdef HAVE_POLL
 
52
#   include <poll.h>
 
53
#endif
 
54
 
 
55
#include <vlc_network.h>
 
56
#include <vlc_url.h>
 
57
#include <vlc_vlm.h>
52
58
 
53
59
#define READ_MODE_PWD 1
54
60
#define READ_MODE_CMD 2
88
94
    set_category( CAT_INTERFACE );
89
95
    set_subcategory( SUBCAT_INTERFACE_CONTROL );
90
96
    add_string( "telnet-host", "", NULL, TELNETHOST_TEXT,
91
 
                 TELNETHOST_LONGTEXT, VLC_TRUE );
 
97
                 TELNETHOST_LONGTEXT, true );
92
98
    add_integer( "telnet-port", TELNETPORT_DEFAULT, NULL, TELNETPORT_TEXT,
93
 
                 TELNETPORT_LONGTEXT, VLC_TRUE );
94
 
    add_string( "telnet-password", TELNETPWD_DEFAULT, NULL, TELNETPWD_TEXT,
95
 
                TELNETPWD_LONGTEXT, VLC_TRUE );
96
 
    set_description( _("VLM remote control interface") );
97
 
    add_category_hint( "VLM", NULL, VLC_FALSE );
 
99
                 TELNETPORT_LONGTEXT, true );
 
100
    add_password( "telnet-password", TELNETPWD_DEFAULT, NULL, TELNETPWD_TEXT,
 
101
                TELNETPWD_LONGTEXT, true );
 
102
    set_description( N_("VLM remote control interface") );
 
103
    add_category_hint( "VLM", NULL, false );
98
104
    set_capability( "interface", 0 );
99
105
    set_callbacks( Open , Close );
100
106
vlc_module_end();
118
124
} telnet_client_t;
119
125
 
120
126
static char *MessageToString( vlm_message_t *, int );
121
 
static void Write_message( telnet_client_t *, vlm_message_t *, char *, int );
 
127
static void Write_message( telnet_client_t *, vlm_message_t *, const char *, int );
122
128
 
123
129
struct intf_sys_t
124
130
{
128
134
   vlm_t           *mediatheque;
129
135
};
130
136
 
131
 
/* 
 
137
/*
132
138
 * getPort: Decide which port to use. There are two possibilities to
133
139
 * specify a port: integrated in the --telnet-host option with :PORT
134
140
 * or using the --telnet-port option. The --telnet-port option has
135
 
 * precedence. 
136
 
 * This code relies upon the fact the url.i_port is 0 if the :PORT 
 
141
 * precedence.
 
142
 * This code relies upon the fact the url.i_port is 0 if the :PORT
137
143
 * option is missing from --telnet-host.
138
144
 */
139
 
static int getPort(intf_thread_t *p_intf, vlc_url_t url, int i_port)
 
145
static int getPort(intf_thread_t *p_intf, const vlc_url_t *url, int i_port)
140
146
{
141
 
    // Print error if two different ports have been specified
142
 
    if (url.i_port != 0  &&
143
 
        i_port != TELNETPORT_DEFAULT && 
144
 
        url.i_port != i_port )
145
 
    {
146
 
            msg_Err( p_intf, "ignoring port %d and using %d", url.i_port,
147
 
                 i_port);
148
 
    }
149
 
    if (i_port != TELNETPORT_DEFAULT)
150
 
    {
151
 
            return i_port;
152
 
    }
153
 
    if (url.i_port != 0)
154
 
    {
155
 
            return url.i_port;
156
 
    }
 
147
    if (i_port == TELNETPORT_DEFAULT && url->i_port != 0)
 
148
        i_port = url->i_port;
 
149
    if (url->i_port != 0 && url->i_port != i_port)
 
150
        // Print error if two different ports have been specified
 
151
        msg_Warn( p_intf, "ignoring port %d (using %d)", url->i_port, i_port );
157
152
    return i_port;
158
153
}
159
154
 
180
175
    psz_address  = config_GetPsz( p_intf, "telnet-host" );
181
176
 
182
177
    vlc_UrlParse(&url, psz_address, 0);
 
178
    free( psz_address );
183
179
 
184
180
    // There might be two ports given, resolve any potentially
185
181
    // conflict
186
 
    url.i_port = getPort(p_intf, url, i_telnetport);
 
182
    url.i_port = getPort(p_intf, &url, i_telnetport);
187
183
 
188
184
    p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
189
 
    if( ( p_intf->p_sys->pi_fd = net_ListenTCP( p_intf, url.psz_host, url.i_port ) )
190
 
                == NULL )
 
185
    if( !p_intf->p_sys )
 
186
    {
 
187
        vlm_Delete( mediatheque );
 
188
        vlc_UrlClean( &url );
 
189
        return VLC_ENOMEM;
 
190
    }
 
191
    if( ( p_intf->p_sys->pi_fd = net_ListenTCP( p_intf, url.psz_host, url.i_port ) ) == NULL )
191
192
    {
192
193
        msg_Err( p_intf, "cannot listen for telnet" );
193
 
        vlc_UrlClean(&url);
194
 
        free( psz_address );
 
194
        vlm_Delete( mediatheque );
 
195
        vlc_UrlClean( &url );
195
196
        free( p_intf->p_sys );
196
197
        return VLC_EGENERIC;
197
198
    }
198
 
    msg_Info( p_intf, 
 
199
    msg_Info( p_intf,
199
200
              "telnet interface started on interface %s %d",
200
201
              url.psz_host, url.i_port );
201
202
 
204
205
    p_intf->p_sys->mediatheque = mediatheque;
205
206
    p_intf->pf_run = Run;
206
207
 
207
 
    vlc_UrlClean(&url);
208
 
    free( psz_address );
 
208
    vlc_UrlClean( &url );
209
209
    return VLC_SUCCESS;
210
210
}
211
211
 
221
221
    for( i = 0; i < p_sys->i_clients; i++ )
222
222
    {
223
223
        telnet_client_t *cl = p_sys->clients[i];
224
 
 
225
224
        net_Close( cl->fd );
 
225
        free( cl->buffer_write );
226
226
        free( cl );
227
227
    }
228
 
    if( p_sys->clients != NULL ) free( p_sys->clients );
 
228
    free( p_sys->clients );
229
229
 
230
230
    net_ListenClose( p_sys->pi_fd );
231
231
 
240
240
static void Run( intf_thread_t *p_intf )
241
241
{
242
242
    intf_sys_t     *p_sys = p_intf->p_sys;
243
 
    struct timeval  timeout;
244
243
    char           *psz_password;
 
244
    unsigned        nlisten = 0;
 
245
 
 
246
    for (const int *pfd = p_sys->pi_fd; *pfd != -1; pfd++)
 
247
        nlisten++; /* How many listening sockets do we have? */
245
248
 
246
249
    psz_password = config_GetPsz( p_intf, "telnet-password" );
247
250
 
248
 
    while( !p_intf->b_die )
 
251
    while( !intf_ShouldDie( p_intf ) )
249
252
    {
250
 
        fd_set fds_read, fds_write;
251
 
        int    i_handle_max = 0;
252
 
        int    i_ret, i_len, fd, i;
253
 
 
254
 
        /* if a new client wants to communicate */
255
 
        fd = net_Accept( p_intf, p_sys->pi_fd, p_sys->i_clients > 0 ? 0 : -1 );
256
 
        if( fd > 0 )
257
 
        {
258
 
            telnet_client_t *cl;
259
 
 
260
 
            /* to be non blocking */
261
 
#if defined( WIN32 ) || defined( UNDER_CE )
262
 
            {
263
 
                unsigned long i_dummy = 1;
264
 
                ioctlsocket( fd, FIONBIO, &i_dummy );
265
 
            }
266
 
#else
267
 
            fcntl( fd, F_SETFL, O_NONBLOCK );
268
 
#endif
269
 
            cl = malloc( sizeof( telnet_client_t ));
270
 
            cl->i_tel_cmd = 0;
271
 
            cl->fd = fd;
272
 
            cl->buffer_write = NULL;
273
 
            cl->p_buffer_write = cl->buffer_write;
274
 
            Write_message( cl, NULL, "Password: \xff\xfb\x01", WRITE_MODE_PWD );
275
 
 
276
 
            TAB_APPEND( p_sys->i_clients, p_sys->clients, cl );
277
 
        }
278
 
 
279
 
        /* to do a proper select */
280
 
        FD_ZERO( &fds_read );
281
 
        FD_ZERO( &fds_write );
282
 
 
283
 
        for( i = 0 ; i < p_sys->i_clients ; i++ )
 
253
        unsigned ncli = p_sys->i_clients;
 
254
        struct pollfd ufd[ncli + nlisten];
 
255
 
 
256
        for (unsigned i = 0; i < ncli; i++)
284
257
        {
285
258
            telnet_client_t *cl = p_sys->clients[i];
286
259
 
287
 
            if( cl->i_mode == WRITE_MODE_PWD || cl->i_mode == WRITE_MODE_CMD )
288
 
            {
289
 
                FD_SET( cl->fd , &fds_write );
290
 
            }
 
260
            ufd[i].fd = cl->fd;
 
261
            if( (cl->i_mode == WRITE_MODE_PWD) || (cl->i_mode == WRITE_MODE_CMD) )
 
262
                ufd[i].events = POLLOUT;
291
263
            else
292
 
            {
293
 
                FD_SET( cl->fd , &fds_read );
294
 
            }
295
 
            i_handle_max = __MAX( i_handle_max, cl->fd );
296
 
        }
297
 
 
298
 
        timeout.tv_sec = 0;
299
 
        timeout.tv_usec = 500*1000;
300
 
 
301
 
        i_ret = select( i_handle_max + 1, &fds_read, &fds_write, 0, &timeout );
302
 
        if( i_ret == -1 && errno != EINTR )
303
 
        {
304
 
            msg_Warn( p_intf, "cannot select sockets" );
305
 
            msleep( 1000 );
306
 
            continue;
307
 
        }
308
 
        else if( i_ret <= 0 )
309
 
        {
310
 
            continue;
 
264
                ufd[i].events = POLLIN;
 
265
            ufd[i].revents = 0;
 
266
        }
 
267
 
 
268
        for (unsigned i = 0; i < nlisten; i++)
 
269
        {
 
270
            ufd[ncli + i].fd = p_sys->pi_fd[i];
 
271
            ufd[ncli + i].events = POLLIN;
 
272
            ufd[ncli + i].revents = 0;
 
273
        }
 
274
 
 
275
        /* FIXME: arbitrary tick */
 
276
        switch (poll (ufd, sizeof (ufd) / sizeof (ufd[0]), 500))
 
277
        {
 
278
            case -1:
 
279
                if (net_errno != EINTR)
 
280
                {
 
281
                    msg_Err (p_intf, "network poll error");
 
282
                    msleep (1000);
 
283
                    continue;
 
284
                }
 
285
            case 0:
 
286
                continue;
311
287
        }
312
288
 
313
289
        /* check if there is something to do with the socket */
314
 
        for( i = 0 ; i < p_sys->i_clients ; i++ )
 
290
        for (unsigned i = 0; i < ncli; i++)
315
291
        {
316
292
            telnet_client_t *cl = p_sys->clients[i];
317
293
 
318
 
            if( FD_ISSET(cl->fd , &fds_write) && cl->i_buffer_write > 0 )
319
 
            {
320
 
                i_len = send( cl->fd , cl->p_buffer_write ,
321
 
                              cl->i_buffer_write , 0 );
 
294
            if (ufd[i].revents & (POLLERR|POLLHUP))
 
295
            {
 
296
            drop:
 
297
                net_Close( cl->fd );
 
298
                TAB_REMOVE( p_intf->p_sys->i_clients ,
 
299
                            p_intf->p_sys->clients , cl );
 
300
                free( cl );
 
301
                continue;
 
302
            }
 
303
 
 
304
            if (ufd[i].revents & POLLOUT && (cl->i_buffer_write > 0))
 
305
            {
 
306
                ssize_t i_len;
 
307
 
 
308
                i_len = send( cl->fd, cl->p_buffer_write ,
 
309
                              cl->i_buffer_write, 0 );
322
310
                if( i_len > 0 )
323
311
                {
324
312
                    cl->p_buffer_write += i_len;
325
313
                    cl->i_buffer_write -= i_len;
326
314
                }
327
315
            }
328
 
            else if( FD_ISSET( cl->fd, &fds_read) )
 
316
            if (ufd[i].revents & POLLIN)
329
317
            {
330
 
                int i_end = 0;
331
 
                int i_recv;
 
318
                bool end = false;
 
319
                ssize_t i_recv;
332
320
 
333
 
                while( (i_recv=recv( cl->fd, cl->p_buffer_read, 1, 0 )) > 0 &&
334
 
                       cl->p_buffer_read - cl->buffer_read < 999 )
 
321
                while( ((i_recv=recv( cl->fd, cl->p_buffer_read, 1, 0 )) > 0) &&
 
322
                       ((cl->p_buffer_read - cl->buffer_read) < 999) )
335
323
                {
336
324
                    switch( cl->i_tel_cmd )
337
325
                    {
342
330
                            break;
343
331
                        case '\n':
344
332
                            *cl->p_buffer_read = '\n';
345
 
                            i_end = 1;
 
333
                            end = true;
346
334
                            break;
347
335
                        case TEL_IAC: // telnet specific command
348
336
                            cl->i_tel_cmd = 1;
373
361
                        break;
374
362
                    }
375
363
 
376
 
                    if( i_end != 0 ) break;
 
364
                    if( end ) break;
377
365
                }
378
366
 
379
 
                if( cl->p_buffer_read - cl->buffer_read == 999 )
 
367
                if( (cl->p_buffer_read - cl->buffer_read) == 999 )
380
368
                {
381
369
                    Write_message( cl, NULL, "Line too long\r\n",
382
370
                                   cl->i_mode + 2 );
383
371
                }
384
372
 
385
 
                if( i_recv == 0  || ( i_recv == -1 &&  errno != EAGAIN && errno != 0 ) )
386
 
                {
387
 
                    net_Close( cl->fd );
388
 
                    TAB_REMOVE( p_intf->p_sys->i_clients ,
389
 
                                p_intf->p_sys->clients , cl );
390
 
                    free( cl );
391
 
                }
 
373
                if (i_recv <= 0 && ( end || errno != EAGAIN ) )
 
374
                    goto drop;
392
375
            }
393
376
        }
394
377
 
395
378
        /* and now we should bidouille the data we received / send */
396
 
        for( i = 0 ; i < p_sys->i_clients ; i++ )
 
379
        for(int i = 0 ; i < p_sys->i_clients ; i++ )
397
380
        {
398
381
            telnet_client_t *cl = p_sys->clients[i];
399
382
 
406
389
                     *cl->p_buffer_read == '\n' )
407
390
            {
408
391
                *cl->p_buffer_read = '\0';
409
 
                if( strcmp( psz_password, cl->buffer_read ) == 0 )
 
392
                if( !psz_password || !strcmp( psz_password, cl->buffer_read ) )
410
393
                {
411
394
                    Write_message( cl, NULL, "\xff\xfc\x01\r\nWelcome, "
412
395
                                   "Master\r\n> ", WRITE_MODE_CMD );
430
413
                    net_Close( cl->fd );
431
414
                    TAB_REMOVE( p_intf->p_sys->i_clients ,
432
415
                                p_intf->p_sys->clients , cl );
 
416
                    free( cl->buffer_write );
433
417
                    free( cl );
434
418
                }
435
419
                else if( !strncmp( cl->buffer_read, "shutdown", 8 ) )
436
420
                {
437
421
                    msg_Err( p_intf, "shutdown requested" );
438
 
                    p_intf->p_vlc->b_die = VLC_TRUE;
 
422
                    vlc_object_kill( p_intf->p_libvlc );
 
423
                }
 
424
                else if( *cl->buffer_read == '@'
 
425
                          && strchr( cl->buffer_read, ' ' ) )
 
426
                {
 
427
                    /* Module specific commands (use same syntax as in the
 
428
                     * rc interface) */
 
429
                    char *psz_name = cl->buffer_read + 1;
 
430
                    char *psz_cmd, *psz_arg, *psz_msg;
 
431
                    int i_ret;
 
432
 
 
433
                    psz_cmd = strchr( cl->buffer_read, ' ' );
 
434
                    *psz_cmd = '\0';  psz_cmd++;
 
435
                    if( ( psz_arg = strchr( psz_cmd, '\n' ) ) ) *psz_arg = '\0';
 
436
                    if( ( psz_arg = strchr( psz_cmd, '\r' ) ) ) *psz_arg = '\0';
 
437
                    if( ( psz_arg = strchr( psz_cmd, ' ' ) )
 
438
                        && *psz_arg )
 
439
                    {
 
440
                        *psz_arg = '\0';
 
441
                        psz_arg++;
 
442
                    }
 
443
 
 
444
                    i_ret = var_Command( p_intf, psz_name, psz_cmd, psz_arg,
 
445
                                         &psz_msg );
 
446
 
 
447
                    if( psz_msg )
 
448
                    {
 
449
                        vlm_message_t *message;
 
450
                        message = vlm_MessageNew( "Module command", psz_msg );
 
451
                        Write_message( cl, message, NULL, WRITE_MODE_CMD );
 
452
                        vlm_MessageDelete( message );
 
453
                        free( psz_msg );
 
454
                    }
439
455
                }
440
456
                else
441
457
                {
446
462
 
447
463
                    vlm_ExecuteCommand( p_sys->mediatheque, cl->buffer_read,
448
464
                                        &message );
 
465
                    if( !strncmp( cl->buffer_read, "help", 4 ) )
 
466
                    {
 
467
                        vlm_message_t *p_my_help =
 
468
                            vlm_MessageNew( "Telnet Specific Commands:", NULL );
 
469
                        vlm_MessageAdd( p_my_help,
 
470
                            vlm_MessageNew( "logout, quit, exit" , NULL ) );
 
471
                        vlm_MessageAdd( p_my_help,
 
472
                            vlm_MessageNew( "shutdown" , NULL ) );
 
473
                        vlm_MessageAdd( p_my_help,
 
474
                            vlm_MessageNew( "@moduleinstance command argument",
 
475
                                             NULL) );
 
476
                        vlm_MessageAdd( message, p_my_help );
 
477
                    }
449
478
                    Write_message( cl, message, NULL, WRITE_MODE_CMD );
450
479
                    vlm_MessageDelete( message );
451
480
                }
452
481
            }
453
482
        }
 
483
 
 
484
        /* handle new connections */
 
485
        for (unsigned i = 0; i < nlisten; i++)
 
486
        {
 
487
            int fd;
 
488
 
 
489
            if (ufd[ncli + i].revents == 0)
 
490
                continue;
 
491
 
 
492
            fd = net_AcceptSingle (VLC_OBJECT(p_intf), ufd[ncli + i].fd);
 
493
            if (fd == -1)
 
494
                continue;
 
495
 
 
496
            telnet_client_t *cl = malloc( sizeof( telnet_client_t ));
 
497
            if (cl == NULL)
 
498
            {
 
499
                net_Close (fd);
 
500
                continue;
 
501
            }
 
502
 
 
503
            memset( cl, 0, sizeof(telnet_client_t) );
 
504
            cl->i_tel_cmd = 0;
 
505
            cl->fd = fd;
 
506
            cl->buffer_write = NULL;
 
507
            cl->p_buffer_write = cl->buffer_write;
 
508
            Write_message( cl, NULL,
 
509
                           "Password: \xff\xfb\x01" , WRITE_MODE_PWD );
 
510
            TAB_APPEND( p_sys->i_clients, p_sys->clients, cl );
 
511
        }
454
512
    }
455
 
 
456
513
    free( psz_password );
457
514
}
458
515
 
459
516
static void Write_message( telnet_client_t *client, vlm_message_t *message,
460
 
                           char *string_message, int i_mode )
 
517
                           const char *string_message, int i_mode )
461
518
{
462
519
    char *psz_message;
463
520
 
464
521
    client->p_buffer_read = client->buffer_read;
465
522
    (client->p_buffer_read)[0] = 0; // if (cl->p_buffer_read)[0] = '\n'
466
 
    if( client->buffer_write ) free( client->buffer_write );
 
523
    free( client->buffer_write );
467
524
 
468
525
    /* generate the psz_message string */
469
526
    if( message )