telnet.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:15k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * telnet.c: VLM interface plugin
  3.  *****************************************************************************
  4.  * Copyright (C) 2000, 2001 VideoLAN
  5.  * $Id: telnet.c 9083 2004-10-30 10:36:07Z gbazin $
  6.  *
  7.  * Authors: Simon Latapie <garf@videolan.org>
  8.  *          Laurent Aimar <fenrir@videolan.org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <stdlib.h>                                      /* malloc(), free() */
  28. #include <vlc/vlc.h>
  29. #include <vlc/intf.h>
  30. #include <vlc/input.h>
  31. #include <sys/stat.h>
  32. #include <errno.h>
  33. #include <fcntl.h>
  34. #ifdef HAVE_SYS_TIME_H
  35. #    include <sys/time.h>
  36. #endif
  37. #ifdef HAVE_UNISTD_H
  38. #   include <unistd.h>
  39. #endif
  40. #if defined( UNDER_CE )
  41. #   include <winsock.h>
  42. #elif defined( WIN32 )
  43. #   include <winsock2.h>
  44. #else
  45. #   include <sys/socket.h>
  46. #endif
  47. #include "network.h"
  48. #include "vlc_vlm.h"
  49. #define READ_MODE_PWD 1
  50. #define READ_MODE_CMD 2
  51. #define WRITE_MODE_PWD 3 // when we write the word "Password:"
  52. #define WRITE_MODE_CMD 4
  53. /* telnet commands */
  54. #define TEL_WILL    251
  55. #define TEL_WONT    252
  56. #define TEL_DO      253
  57. #define TEL_DONT    254
  58. #define TEL_IAC     255
  59. #define TEL_ECHO    1
  60. /*****************************************************************************
  61.  * Module descriptor
  62.  *****************************************************************************/
  63. static int  Open ( vlc_object_t * );
  64. static void Close( vlc_object_t * );
  65. #define TELNETPORT_TEXT N_( "Telnet Interface port" )
  66. #define TELNETPORT_LONGTEXT N_( "Default to 4212" )
  67. #define TELNETPWD_TEXT N_( "Telnet Interface password" )
  68. #define TELNETPWD_LONGTEXT N_( "Default to admin" )
  69. vlc_module_begin();
  70.     add_integer( "telnet-port", 4212, NULL, TELNETPORT_TEXT,
  71.                  TELNETPORT_LONGTEXT, VLC_TRUE );
  72.     add_string( "telnet-password", "admin", NULL, TELNETPWD_TEXT,
  73.                 TELNETPWD_LONGTEXT, VLC_TRUE );
  74.     set_description( _("Telnet remote control interface") );
  75.     add_category_hint( "VLM", NULL, VLC_FALSE );
  76.     set_capability( "interface", 0 );
  77.     set_callbacks( Open , Close );
  78. vlc_module_end();
  79. /*****************************************************************************
  80.  * Local prototypes.
  81.  *****************************************************************************/
  82. static void Run( intf_thread_t * );
  83. typedef struct
  84. {
  85.     int        i_mode; /* read or write */
  86.     int        fd;
  87.     uint8_t    buffer_read[1000]; // 1000 byte per command should be sufficient
  88.     char      *buffer_write;
  89.     uint8_t   *p_buffer_read;
  90.     uint8_t   *p_buffer_write; // the position in the buffer
  91.     int        i_buffer_write; // the number of byte we still have to send
  92.     int        i_tel_cmd; // for specific telnet commands
  93. } telnet_client_t;
  94. static char *MessageToString( vlm_message_t *, int );
  95. static void Write_message( telnet_client_t *, vlm_message_t *, char *, int );
  96. struct intf_sys_t
  97. {
  98.    telnet_client_t **clients;
  99.    int             i_clients;
  100.    int             fd;
  101.    vlm_t           *mediatheque;
  102. };
  103. /*****************************************************************************
  104.  * Open: initialize dummy interface
  105.  *****************************************************************************/
  106. static int Open( vlc_object_t *p_this )
  107. {
  108.     intf_thread_t *p_intf = (intf_thread_t*) p_this;
  109.     vlm_t *mediatheque;
  110.     int i_telnetport;
  111.     if( !(mediatheque = vlm_New( p_intf )) )
  112.     {
  113.         msg_Err( p_intf, "cannot start VLM" );
  114.         return VLC_EGENERIC;
  115.     }
  116.     msg_Info( p_intf, "Using the VLM interface plugin..." );
  117.     i_telnetport = config_GetInt( p_intf, "telnet-port" );
  118.     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
  119.     if( ( p_intf->p_sys->fd = net_ListenTCP( p_intf , "", i_telnetport ) ) < 0 )
  120.     {
  121.         msg_Err( p_intf, "cannot listen for telnet" );
  122.         free( p_intf->p_sys );
  123.         return VLC_EGENERIC;
  124.     }
  125.     msg_Info( p_intf, "Telnet interface started on port: %d", i_telnetport );
  126.     p_intf->p_sys->i_clients   = 0;
  127.     p_intf->p_sys->clients     = NULL;
  128.     p_intf->p_sys->mediatheque = mediatheque;
  129.     p_intf->pf_run = Run;
  130.     return VLC_SUCCESS;
  131. }
  132. /*****************************************************************************
  133.  * Close:
  134.  *****************************************************************************/
  135. static void Close( vlc_object_t *p_this )
  136. {
  137.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  138.     intf_sys_t    *p_sys  = p_intf->p_sys;
  139.     int i;
  140.     for( i = 0; i < p_sys->i_clients; i++ )
  141.     {
  142.         telnet_client_t *cl = p_sys->clients[i];
  143.         net_Close( cl->fd );
  144.         free( cl );
  145.     }
  146.     if( p_sys->clients != NULL ) free( p_sys->clients );
  147.     net_Close( p_sys->fd );
  148.     vlm_Delete( p_sys->mediatheque );
  149.     free( p_sys );
  150. }
  151. /*****************************************************************************
  152.  * Run: main loop
  153.  *****************************************************************************/
  154. static void Run( intf_thread_t *p_intf )
  155. {
  156.     intf_sys_t     *p_sys = p_intf->p_sys;
  157.     struct timeval  timeout;
  158.     char           *psz_password;
  159.     psz_password = config_GetPsz( p_intf, "telnet-password" );
  160.     while( !p_intf->b_die )
  161.     {
  162.         fd_set fds_read, fds_write;
  163.         int    i_handle_max = 0;
  164.         int    i_ret, i_len, fd, i;
  165.         /* if a new client wants to communicate */
  166.         fd = net_Accept( p_intf, p_sys->fd, p_sys->i_clients > 0 ? 0 : -1 );
  167.         if( fd > 0 )
  168.         {
  169.             telnet_client_t *cl;
  170.             /* to be non blocking */
  171. #if defined( WIN32 ) || defined( UNDER_CE )
  172.             {
  173.                 unsigned long i_dummy = 1;
  174.                 ioctlsocket( fd, FIONBIO, &i_dummy );
  175.             }
  176. #else
  177.             fcntl( fd, F_SETFL, O_NONBLOCK );
  178. #endif
  179.             cl = malloc( sizeof( telnet_client_t ));
  180.             cl->i_tel_cmd = 0;
  181.             cl->fd = fd;
  182.             cl->buffer_write = NULL;
  183.             cl->p_buffer_write = cl->buffer_write;
  184.             Write_message( cl, NULL, "Password:xffxfbx01", WRITE_MODE_PWD );
  185.             TAB_APPEND( p_sys->i_clients, p_sys->clients, cl );
  186.         }
  187.         /* to do a proper select */
  188.         FD_ZERO( &fds_read );
  189.         FD_ZERO( &fds_write );
  190.         for( i = 0 ; i < p_sys->i_clients ; i++ )
  191.         {
  192.             telnet_client_t *cl = p_sys->clients[i];
  193.             if( cl->i_mode == WRITE_MODE_PWD || cl->i_mode == WRITE_MODE_CMD )
  194.             {
  195.                 FD_SET( cl->fd , &fds_write );
  196.             }
  197.             else
  198.             {
  199.                 FD_SET( cl->fd , &fds_read );
  200.             }
  201.             i_handle_max = __MAX( i_handle_max, cl->fd );
  202.         }
  203.         timeout.tv_sec = 0;
  204.         timeout.tv_usec = 500*1000;
  205.         i_ret = select( i_handle_max + 1, &fds_read, &fds_write, 0, &timeout );
  206.         if( i_ret == -1 && errno != EINTR )
  207.         {
  208.             msg_Warn( p_intf, "cannot select sockets" );
  209.             msleep( 1000 );
  210.             continue;
  211.         }
  212.         else if( i_ret <= 0 )
  213.         {
  214.             continue;
  215.         }
  216.         /* check if there is something to do with the socket */
  217.         for( i = 0 ; i < p_sys->i_clients ; i++ )
  218.         {
  219.             telnet_client_t *cl = p_sys->clients[i];
  220.             if( FD_ISSET(cl->fd , &fds_write) && cl->i_buffer_write > 0 )
  221.             {
  222.                 i_len = send( cl->fd , cl->p_buffer_write ,
  223.                               cl->i_buffer_write , 0 );
  224.                 if( i_len > 0 )
  225.                 {
  226.                     cl->p_buffer_write += i_len;
  227.                     cl->i_buffer_write -= i_len;
  228.                 }
  229.             }
  230.             else if( FD_ISSET( cl->fd, &fds_read) )
  231.             {
  232.                 int i_end = 0;
  233.                 while( recv( cl->fd, cl->p_buffer_read, 1, 0 ) > 0 &&
  234.                        cl->p_buffer_read - cl->buffer_read < 999 )
  235.                 {
  236.                     switch( cl->i_tel_cmd )
  237.                     {
  238.                     case 0:
  239.                         switch( *cl->p_buffer_read )
  240.                         {
  241.                         case 'r':
  242.                             break;
  243.                         case 'n':
  244.                             *cl->p_buffer_read = 'n';
  245.                             i_end = 1;
  246.                             break;
  247.                         case TEL_IAC: // telnet specific command
  248.                             cl->i_tel_cmd = 1;
  249.                             cl->p_buffer_read++;
  250.                             break;
  251.                         default:
  252.                             cl->p_buffer_read++;
  253.                             break;
  254.                         }
  255.                         break;
  256.                     case 1:
  257.                         switch( *cl->p_buffer_read )
  258.                         {
  259.                         case TEL_WILL: case TEL_WONT:
  260.                         case TEL_DO: case TEL_DONT:
  261.                             cl->i_tel_cmd++;
  262.                             cl->p_buffer_read++;
  263.                             break;
  264.                         default:
  265.                             cl->i_tel_cmd = 0;
  266.                             cl->p_buffer_read--;
  267.                             break;
  268.                         }
  269.                         break;
  270.                     case 2:
  271.                         cl->i_tel_cmd = 0;
  272.                         cl->p_buffer_read -= 2;
  273.                         break;
  274.                     }
  275.                     if( i_end != 0 ) break;
  276.                 }
  277.                 if( cl->p_buffer_read - cl->buffer_read == 999 )
  278.                 {
  279.                     Write_message( cl, NULL, "Line too longrn",
  280.                                    cl->i_mode + 2 );
  281.                 }
  282.             }
  283.         }
  284.         /* and now we should bidouille the data we received / send */
  285.         for( i = 0 ; i < p_sys->i_clients ; i++ )
  286.         {
  287.             telnet_client_t *cl = p_sys->clients[i];
  288.             if( cl->i_mode >= WRITE_MODE_PWD && cl->i_buffer_write == 0 )
  289.             {
  290.                // we have finished to send
  291.                cl->i_mode -= 2; // corresponding READ MODE
  292.             }
  293.             else if( cl->i_mode == READ_MODE_PWD &&
  294.                      *cl->p_buffer_read == 'n' )
  295.             {
  296.                 *cl->p_buffer_read = '';
  297.                 if( strcmp( psz_password, cl->buffer_read ) == 0 )
  298.                 {
  299.                     Write_message( cl, NULL, "xffxfcx01rnWelcome, "
  300.                                    "Masterrn> ", WRITE_MODE_CMD );
  301.                 }
  302.                 else
  303.                 {
  304.                     /* wrong password */
  305.                     Write_message( cl, NULL, "rnTry again, you polio:",
  306.                                    WRITE_MODE_PWD );
  307.                 }
  308.             }
  309.             else if( cl->i_mode == READ_MODE_CMD &&
  310.                      *cl->p_buffer_read == 'n' )
  311.             {
  312.                 /* ok, here is a command line */
  313.                 if( !strncmp( cl->buffer_read, "logout", 6 ) ||
  314.                     !strncmp( cl->buffer_read, "quit", 4 )  ||
  315.                     !strncmp( cl->buffer_read, "exit", 4 ) )
  316.                 {
  317.                     net_Close( cl->fd );
  318.                     TAB_REMOVE( p_intf->p_sys->i_clients ,
  319.                                 p_intf->p_sys->clients , cl );
  320.                     free( cl );
  321.                 }
  322.                 else if( !strncmp( cl->buffer_read, "shutdown", 8 ) )
  323.                 {
  324.                     msg_Err( p_intf, "shutdown requested" );
  325.                     p_intf->p_vlc->b_die = VLC_TRUE;
  326.                 }
  327.                 else
  328.                 {
  329.                     vlm_message_t *message;
  330.                     /* create a standard string */
  331.                     *cl->p_buffer_read = '';
  332.                     vlm_ExecuteCommand( p_sys->mediatheque, cl->buffer_read,
  333.                                         &message );
  334.                     Write_message( cl, message, NULL, WRITE_MODE_CMD );
  335.                     vlm_MessageDelete( message );
  336.                 }
  337.             }
  338.         }
  339.     }
  340. }
  341. static void Write_message( telnet_client_t *client, vlm_message_t *message,
  342.                            char *string_message, int i_mode )
  343. {
  344.     char *psz_message;
  345.     client->p_buffer_read = client->buffer_read;
  346.     (client->p_buffer_read)[0] = 0; // if (cl->p_buffer_read)[0] = 'n'
  347.     if( client->buffer_write ) free( client->buffer_write );
  348.     /* generate the psz_message string */
  349.     if( message )
  350.     {
  351.         /* ok, look for vlm_message_t */
  352.         psz_message = MessageToString( message, 0 );
  353.     }
  354.     else
  355.     {
  356.         /* it is a basic string_message */
  357.         psz_message = strdup( string_message );
  358.     }
  359.     client->buffer_write = client->p_buffer_write = psz_message;
  360.     client->i_buffer_write = strlen( psz_message );
  361.     client->i_mode = i_mode;
  362. }
  363. /* We need the level of the message to put a beautiful indentation.
  364.  * first level is 0 */
  365. static char *MessageToString( vlm_message_t *message, int i_level )
  366. {
  367. #define STRING_CR "rn"
  368. #define STRING_TAIL "> "
  369.     char *psz_message;
  370.     int i, i_message = sizeof( STRING_TAIL );
  371.     if( !message || !message->psz_name )
  372.     {
  373.         return strdup( STRING_CR STRING_TAIL );
  374.     }
  375.     else if( !i_level && !message->i_child && !message->psz_value  )
  376.     {
  377.         /* A command is successful. Don't write anything */
  378.         return strdup( STRING_CR STRING_TAIL );
  379.     }
  380.     i_message += strlen( message->psz_name ) + i_level * sizeof( "    " ) + 1;
  381.     psz_message = malloc( i_message ); *psz_message = 0;
  382.     for( i = 0; i < i_level; i++ ) strcat( psz_message, "    " );
  383.     strcat( psz_message, message->psz_name );
  384.     if( message->psz_value )
  385.     {
  386.         i_message += sizeof( " : " ) + strlen( message->psz_value ) +
  387.             sizeof( STRING_CR );
  388.         psz_message = realloc( psz_message, i_message );
  389.         strcat( psz_message, " : " );
  390.         strcat( psz_message, message->psz_value );
  391.         strcat( psz_message, STRING_CR );
  392.     }
  393.     else
  394.     {
  395.         i_message += sizeof( STRING_CR );
  396.         psz_message = realloc( psz_message, i_message );
  397.         strcat( psz_message, STRING_CR );
  398.     }
  399.     for( i = 0; i < message->i_child; i++ )
  400.     {
  401.         char *child_message =
  402.             MessageToString( message->child[i], i_level + 1 );
  403.         i_message += strlen( child_message );
  404.         psz_message = realloc( psz_message, i_message );
  405.         strcat( psz_message, child_message );
  406.         free( child_message );
  407.     }
  408.     if( i_level == 0 ) strcat( psz_message, STRING_TAIL );
  409.     return psz_message;
  410. }