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();
128
134
vlm_t *mediatheque;
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
136
* This code relies upon the fact the url.i_port is 0 if the :PORT
142
* This code relies upon the fact the url.i_port is 0 if the :PORT
137
143
* option is missing from --telnet-host.
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)
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 )
146
msg_Err( p_intf, "ignoring port %d and using %d", url.i_port,
149
if (i_port != TELNETPORT_DEFAULT)
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 );
180
175
psz_address = config_GetPsz( p_intf, "telnet-host" );
182
177
vlc_UrlParse(&url, psz_address, 0);
184
180
// There might be two ports given, resolve any potentially
186
url.i_port = getPort(p_intf, url, i_telnetport);
182
url.i_port = getPort(p_intf, &url, i_telnetport);
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 ) )
187
vlm_Delete( mediatheque );
188
vlc_UrlClean( &url );
191
if( ( p_intf->p_sys->pi_fd = net_ListenTCP( p_intf, url.psz_host, url.i_port ) ) == NULL )
192
193
msg_Err( p_intf, "cannot listen for telnet" );
194
vlm_Delete( mediatheque );
195
vlc_UrlClean( &url );
195
196
free( p_intf->p_sys );
196
197
return VLC_EGENERIC;
199
200
"telnet interface started on interface %s %d",
200
201
url.psz_host, url.i_port );
240
240
static void Run( intf_thread_t *p_intf )
242
242
intf_sys_t *p_sys = p_intf->p_sys;
243
struct timeval timeout;
244
243
char *psz_password;
244
unsigned nlisten = 0;
246
for (const int *pfd = p_sys->pi_fd; *pfd != -1; pfd++)
247
nlisten++; /* How many listening sockets do we have? */
246
249
psz_password = config_GetPsz( p_intf, "telnet-password" );
248
while( !p_intf->b_die )
251
while( !intf_ShouldDie( p_intf ) )
250
fd_set fds_read, fds_write;
251
int i_handle_max = 0;
252
int i_ret, i_len, fd, i;
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 );
260
/* to be non blocking */
261
#if defined( WIN32 ) || defined( UNDER_CE )
263
unsigned long i_dummy = 1;
264
ioctlsocket( fd, FIONBIO, &i_dummy );
267
fcntl( fd, F_SETFL, O_NONBLOCK );
269
cl = malloc( sizeof( telnet_client_t ));
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 );
276
TAB_APPEND( p_sys->i_clients, p_sys->clients, cl );
279
/* to do a proper select */
280
FD_ZERO( &fds_read );
281
FD_ZERO( &fds_write );
283
for( i = 0 ; i < p_sys->i_clients ; i++ )
253
unsigned ncli = p_sys->i_clients;
254
struct pollfd ufd[ncli + nlisten];
256
for (unsigned i = 0; i < ncli; i++)
285
258
telnet_client_t *cl = p_sys->clients[i];
287
if( cl->i_mode == WRITE_MODE_PWD || cl->i_mode == WRITE_MODE_CMD )
289
FD_SET( cl->fd , &fds_write );
261
if( (cl->i_mode == WRITE_MODE_PWD) || (cl->i_mode == WRITE_MODE_CMD) )
262
ufd[i].events = POLLOUT;
293
FD_SET( cl->fd , &fds_read );
295
i_handle_max = __MAX( i_handle_max, cl->fd );
299
timeout.tv_usec = 500*1000;
301
i_ret = select( i_handle_max + 1, &fds_read, &fds_write, 0, &timeout );
302
if( i_ret == -1 && errno != EINTR )
304
msg_Warn( p_intf, "cannot select sockets" );
308
else if( i_ret <= 0 )
264
ufd[i].events = POLLIN;
268
for (unsigned i = 0; i < nlisten; i++)
270
ufd[ncli + i].fd = p_sys->pi_fd[i];
271
ufd[ncli + i].events = POLLIN;
272
ufd[ncli + i].revents = 0;
275
/* FIXME: arbitrary tick */
276
switch (poll (ufd, sizeof (ufd) / sizeof (ufd[0]), 500))
279
if (net_errno != EINTR)
281
msg_Err (p_intf, "network poll error");
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++)
316
292
telnet_client_t *cl = p_sys->clients[i];
318
if( FD_ISSET(cl->fd , &fds_write) && cl->i_buffer_write > 0 )
320
i_len = send( cl->fd , cl->p_buffer_write ,
321
cl->i_buffer_write , 0 );
294
if (ufd[i].revents & (POLLERR|POLLHUP))
298
TAB_REMOVE( p_intf->p_sys->i_clients ,
299
p_intf->p_sys->clients , cl );
304
if (ufd[i].revents & POLLOUT && (cl->i_buffer_write > 0))
308
i_len = send( cl->fd, cl->p_buffer_write ,
309
cl->i_buffer_write, 0 );
324
312
cl->p_buffer_write += i_len;
325
313
cl->i_buffer_write -= i_len;
328
else if( FD_ISSET( cl->fd, &fds_read) )
316
if (ufd[i].revents & POLLIN)
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) )
336
324
switch( cl->i_tel_cmd )
376
if( i_end != 0 ) break;
379
if( cl->p_buffer_read - cl->buffer_read == 999 )
367
if( (cl->p_buffer_read - cl->buffer_read) == 999 )
381
369
Write_message( cl, NULL, "Line too long\r\n",
382
370
cl->i_mode + 2 );
385
if( i_recv == 0 || ( i_recv == -1 && errno != EAGAIN && errno != 0 ) )
388
TAB_REMOVE( p_intf->p_sys->i_clients ,
389
p_intf->p_sys->clients , cl );
373
if (i_recv <= 0 && ( end || errno != EAGAIN ) )
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++ )
398
381
telnet_client_t *cl = p_sys->clients[i];
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 );
435
419
else if( !strncmp( cl->buffer_read, "shutdown", 8 ) )
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 );
424
else if( *cl->buffer_read == '@'
425
&& strchr( cl->buffer_read, ' ' ) )
427
/* Module specific commands (use same syntax as in the
429
char *psz_name = cl->buffer_read + 1;
430
char *psz_cmd, *psz_arg, *psz_msg;
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, ' ' ) )
444
i_ret = var_Command( p_intf, psz_name, psz_cmd, psz_arg,
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 );
447
463
vlm_ExecuteCommand( p_sys->mediatheque, cl->buffer_read,
465
if( !strncmp( cl->buffer_read, "help", 4 ) )
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",
476
vlm_MessageAdd( message, p_my_help );
449
478
Write_message( cl, message, NULL, WRITE_MODE_CMD );
450
479
vlm_MessageDelete( message );
484
/* handle new connections */
485
for (unsigned i = 0; i < nlisten; i++)
489
if (ufd[ncli + i].revents == 0)
492
fd = net_AcceptSingle (VLC_OBJECT(p_intf), ufd[ncli + i].fd);
496
telnet_client_t *cl = malloc( sizeof( telnet_client_t ));
503
memset( cl, 0, sizeof(telnet_client_t) );
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 );
456
513
free( psz_password );
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 )
462
519
char *psz_message;
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 );
468
525
/* generate the psz_message string */