tcp.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:16k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * tcp.c:
  3.  *****************************************************************************
  4.  * Copyright (C) 2004-2005 the VideoLAN team
  5.  * Copyright (C) 2005-2006 Rémi Denis-Courmont
  6.  * $Id: 0fabdd0afab905728d421f5905e4c07657242b84 $
  7.  *
  8.  * Authors: Laurent Aimar <fenrir@videolan.org>
  9.  *          Rémi Denis-Courmont <rem # videolan.org>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #ifdef HAVE_CONFIG_H
  29. # include "config.h"
  30. #endif
  31. #include <vlc_common.h>
  32. #include <errno.h>
  33. #include <assert.h>
  34. #ifdef HAVE_FCNTL_H
  35. #   include <fcntl.h>
  36. #endif
  37. #ifdef HAVE_SYS_TIME_H
  38. #    include <sys/time.h>
  39. #endif
  40. #ifdef HAVE_UNISTD_H
  41. #   include <unistd.h>
  42. #endif
  43. #ifdef HAVE_POLL
  44. # include <poll.h>
  45. #endif
  46. #include <vlc_network.h>
  47. #if defined (WIN32) || defined (UNDER_CE)
  48. #   undef EINPROGRESS
  49. #   define EINPROGRESS WSAEWOULDBLOCK
  50. #   undef EWOULDBLOCK
  51. #   define EWOULDBLOCK WSAEWOULDBLOCK
  52. #   undef EINTR
  53. #   define EINTR WSAEINTR
  54. #   undef ETIMEDOUT
  55. #   define ETIMEDOUT WSAETIMEDOUT
  56. #endif
  57. #include "libvlc.h" /* vlc_object_waitpipe */
  58. static int SocksNegotiate( vlc_object_t *, int fd, int i_socks_version,
  59.                            const char *psz_user, const char *psz_passwd );
  60. static int SocksHandshakeTCP( vlc_object_t *,
  61.                               int fd, int i_socks_version,
  62.                               const char *psz_user, const char *psz_passwd,
  63.                               const char *psz_host, int i_port );
  64. extern int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
  65.                        int i_protocol );
  66. /*****************************************************************************
  67.  * __net_Connect:
  68.  *****************************************************************************
  69.  * Open a network connection.
  70.  * @return socket handler or -1 on error.
  71.  *****************************************************************************/
  72. int __net_Connect( vlc_object_t *p_this, const char *psz_host, int i_port,
  73.                    int type, int proto )
  74. {
  75.     struct addrinfo hints, *res, *ptr;
  76.     const char      *psz_realhost;
  77.     char            *psz_socks;
  78.     int             i_realport, i_val, i_handle = -1;
  79.     int evfd = vlc_object_waitpipe (p_this);
  80.     if (evfd == -1)
  81.         return -1;
  82.     memset( &hints, 0, sizeof( hints ) );
  83.     hints.ai_socktype = SOCK_STREAM;
  84.     psz_socks = var_CreateGetNonEmptyString( p_this, "socks" );
  85.     if( psz_socks != NULL )
  86.     {
  87.         char *psz = strchr( psz_socks, ':' );
  88.         if( psz )
  89.             *psz++ = '';
  90.         psz_realhost = psz_socks;
  91.         i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
  92.         hints.ai_flags &= ~AI_NUMERICHOST;
  93.         msg_Dbg( p_this, "net: connecting to %s port %d (SOCKS) "
  94.                  "for %s port %d", psz_realhost, i_realport,
  95.                  psz_host, i_port );
  96.         /* We only implement TCP with SOCKS */
  97.         switch( type )
  98.         {
  99.             case 0:
  100.                 type = SOCK_STREAM;
  101.             case SOCK_STREAM:
  102.                 break;
  103.             default:
  104.                 msg_Err( p_this, "Socket type not supported through SOCKS" );
  105.                 free( psz_socks );
  106.                 return -1;
  107.         }
  108.         switch( proto )
  109.         {
  110.             case 0:
  111.                 proto = IPPROTO_TCP;
  112.             case IPPROTO_TCP:
  113.                 break;
  114.             default:
  115.                 msg_Err( p_this, "Transport not supported through SOCKS" );
  116.                 free( psz_socks );
  117.                 return -1;
  118.         }
  119.     }
  120.     else
  121.     {
  122.         psz_realhost = psz_host;
  123.         i_realport = i_port;
  124.         msg_Dbg( p_this, "net: connecting to %s port %d", psz_realhost,
  125.                  i_realport );
  126.     }
  127.     i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
  128.     free( psz_socks );
  129.     if( i_val )
  130.     {
  131.         msg_Err( p_this, "cannot resolve %s port %d : %s", psz_realhost,
  132.                  i_realport, vlc_gai_strerror( i_val ) );
  133.         return -1;
  134.     }
  135.     for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
  136.     {
  137.         int fd = net_Socket( p_this, ptr->ai_family,
  138.                              type ? type : ptr->ai_socktype,
  139.                              proto ? proto : ptr->ai_protocol );
  140.         if( fd == -1 )
  141.         {
  142.             msg_Dbg( p_this, "socket error: %m" );
  143.             continue;
  144.         }
  145.         if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
  146.         {
  147.             int timeout, val;
  148.             if( net_errno != EINPROGRESS && net_errno != EINTR )
  149.             {
  150.                 msg_Err( p_this, "connection failed: %m" );
  151.                 goto next_ai;
  152.             }
  153.             msg_Dbg( p_this, "connection: %m" );
  154.             timeout = var_CreateGetInteger (p_this, "ipv4-timeout");
  155.             if (timeout < 0)
  156.             {
  157.                 msg_Err( p_this, "invalid negative value for ipv4-timeout" );
  158.                 timeout = 0;
  159.             }
  160.             struct pollfd ufd[2] = {
  161.                 { .fd = fd,   .events = POLLOUT },
  162.                 { .fd = evfd, .events = POLLIN },
  163.             };
  164.             do
  165.                 /* NOTE: timeout screwed up if we catch a signal (EINTR) */
  166.                 val = poll (ufd, sizeof (ufd) / sizeof (ufd[0]), timeout);
  167.             while ((val == -1) && (net_errno == EINTR));
  168.             switch (val)
  169.             {
  170.                  case -1: /* error */
  171.                      msg_Err (p_this, "connection polling error: %m");
  172.                      goto next_ai;
  173.                  case 0: /* timeout */
  174.                      msg_Warn (p_this, "connection timed out");
  175.                      goto next_ai;
  176.                  default: /* something happended */
  177.                      if (ufd[1].revents)
  178.                          goto next_ai; /* LibVLC object killed */
  179.             }
  180.             /* There is NO WAY around checking SO_ERROR.
  181.              * Don't ifdef it out!!! */
  182.             if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &val,
  183.                             &(socklen_t){ sizeof (val) }) || val)
  184.             {
  185.                 errno = val;
  186.                 msg_Err (p_this, "connection failed: %m");
  187.                 goto next_ai;
  188.             }
  189.         }
  190.         msg_Dbg( p_this, "connection succeeded (socket = %d)", fd );
  191.         i_handle = fd; /* success! */
  192.         break;
  193. next_ai: /* failure */
  194.         net_Close( fd );
  195.         continue;
  196.     }
  197.     vlc_freeaddrinfo( res );
  198.     if( i_handle == -1 )
  199.         return -1;
  200.     if( psz_socks != NULL )
  201.     {
  202.         /* NOTE: psz_socks already free'd! */
  203.         char *psz_user = var_CreateGetNonEmptyString( p_this, "socks-user" );
  204.         char *psz_pwd  = var_CreateGetNonEmptyString( p_this, "socks-pwd" );
  205.         if( SocksHandshakeTCP( p_this, i_handle, 5, psz_user, psz_pwd,
  206.                                psz_host, i_port ) )
  207.         {
  208.             msg_Err( p_this, "SOCKS handshake failed" );
  209.             net_Close( i_handle );
  210.             i_handle = -1;
  211.         }
  212.         free( psz_user );
  213.         free( psz_pwd );
  214.     }
  215.     return i_handle;
  216. }
  217. int net_AcceptSingle (vlc_object_t *obj, int lfd)
  218. {
  219.     int fd;
  220.     do
  221.         fd = accept (lfd, NULL, NULL);
  222.     while (fd == -1 && errno == EINTR);
  223.     if (fd == -1)
  224.     {
  225.         if (net_errno != EAGAIN && net_errno != EWOULDBLOCK)
  226.             msg_Err (obj, "accept failed (from socket %d): %m", lfd);
  227.         return -1;
  228.     }
  229.     msg_Dbg (obj, "accepted socket %d (from socket %d)", fd, lfd);
  230.     net_SetupSocket (fd);
  231.     return fd;
  232. }
  233. /*****************************************************************************
  234.  * __net_Accept:
  235.  *****************************************************************************
  236.  * Accept a connection on a set of listening sockets and return it
  237.  *****************************************************************************/
  238. int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
  239. {
  240.     int timeout = (i_wait < 0) ? -1 : i_wait / 1000;
  241.     int evfd = vlc_object_waitpipe (p_this);
  242.     assert( pi_fd != NULL );
  243.     for (;;)
  244.     {
  245.         unsigned n = 0;
  246.         while (pi_fd[n] != -1)
  247.             n++;
  248.         struct pollfd ufd[n + 1];
  249.         /* Initialize file descriptor set */
  250.         for (unsigned i = 0; i <= n; i++)
  251.         {
  252.             ufd[i].fd = (i < n) ? pi_fd[i] : evfd;
  253.             ufd[i].events = POLLIN;
  254.             ufd[i].revents = 0;
  255.         }
  256.         switch (poll (ufd, n + (evfd != -1), timeout))
  257.         {
  258.             case -1:
  259.                 if (net_errno == EINTR)
  260.                     continue;
  261.                 msg_Err (p_this, "poll error: %m");
  262.                 return -1;
  263.             case 0:
  264.                 errno = ETIMEDOUT;
  265.                 return -1;
  266.         }
  267.         if (ufd[n].revents)
  268.         {
  269.             errno = EINTR;
  270.             break;
  271.         }
  272.         for (unsigned i = 0; i < n; i++)
  273.         {
  274.             if (ufd[i].revents == 0)
  275.                 continue;
  276.             int sfd = ufd[i].fd;
  277.             int fd = net_AcceptSingle (p_this, sfd);
  278.             if (fd == -1)
  279.                 continue;
  280.             /*
  281.              * Move listening socket to the end to let the others in the
  282.              * set a chance next time.
  283.              */
  284.             memmove (pi_fd + i, pi_fd + i + 1, n - (i + 1));
  285.             pi_fd[n - 1] = sfd;
  286.             return fd;
  287.         }
  288.     }
  289.     return -1;
  290. }
  291. /*****************************************************************************
  292.  * SocksNegotiate:
  293.  *****************************************************************************
  294.  * Negotiate authentication with a SOCKS server.
  295.  *****************************************************************************/
  296. static int SocksNegotiate( vlc_object_t *p_obj,
  297.                            int fd, int i_socks_version,
  298.                            const char *psz_socks_user,
  299.                            const char *psz_socks_passwd )
  300. {
  301.     uint8_t buffer[128+2*256];
  302.     int i_len;
  303.     bool b_auth = false;
  304.     if( i_socks_version != 5 )
  305.         return VLC_SUCCESS;
  306.     /* We negotiate authentication */
  307.     if( ( psz_socks_user == NULL ) && ( psz_socks_passwd == NULL ) )
  308.         b_auth = true;
  309.     buffer[0] = i_socks_version;    /* SOCKS version */
  310.     if( b_auth )
  311.     {
  312.         buffer[1] = 2;                  /* Number of methods */
  313.         buffer[2] = 0x00;               /* - No auth required */
  314.         buffer[3] = 0x02;               /* - USer/Password */
  315.         i_len = 4;
  316.     }
  317.     else
  318.     {
  319.         buffer[1] = 1;                  /* Number of methods */
  320.         buffer[2] = 0x00;               /* - No auth required */
  321.         i_len = 3;
  322.     }
  323.     if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
  324.         return VLC_EGENERIC;
  325.     if( net_Read( p_obj, fd, NULL, buffer, 2, true ) != 2 )
  326.         return VLC_EGENERIC;
  327.     msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
  328.     if( buffer[1] == 0x00 )
  329.     {
  330.         msg_Dbg( p_obj, "socks: no authentication required" );
  331.     }
  332.     else if( buffer[1] == 0x02 )
  333.     {
  334.         int i_len1 = __MIN( strlen(psz_socks_user), 255 );
  335.         int i_len2 = __MIN( strlen(psz_socks_passwd), 255 );
  336.         msg_Dbg( p_obj, "socks: username/password authentication" );
  337.         /* XXX: we don't support user/pwd > 255 (truncated)*/
  338.         buffer[0] = i_socks_version;        /* Version */
  339.         buffer[1] = i_len1;                 /* User length */
  340.         memcpy( &buffer[2], psz_socks_user, i_len1 );
  341.         buffer[2+i_len1] = i_len2;          /* Password length */
  342.         memcpy( &buffer[2+i_len1+1], psz_socks_passwd, i_len2 );
  343.         i_len = 3 + i_len1 + i_len2;
  344.         if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
  345.             return VLC_EGENERIC;
  346.         if( net_Read( p_obj, fd, NULL, buffer, 2, true ) != 2 )
  347.             return VLC_EGENERIC;
  348.         msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
  349.         if( buffer[1] != 0x00 )
  350.         {
  351.             msg_Err( p_obj, "socks: authentication rejected" );
  352.             return VLC_EGENERIC;
  353.         }
  354.     }
  355.     else
  356.     {
  357.         if( b_auth )
  358.             msg_Err( p_obj, "socks: unsupported authentication method %x",
  359.                      buffer[0] );
  360.         else
  361.             msg_Err( p_obj, "socks: authentification needed" );
  362.         return VLC_EGENERIC;
  363.     }
  364.     return VLC_SUCCESS;
  365. }
  366. /*****************************************************************************
  367.  * SocksHandshakeTCP:
  368.  *****************************************************************************
  369.  * Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
  370.  *****************************************************************************/
  371. static int SocksHandshakeTCP( vlc_object_t *p_obj,
  372.                               int fd,
  373.                               int i_socks_version,
  374.                               const char *psz_user, const char *psz_passwd,
  375.                               const char *psz_host, int i_port )
  376. {
  377.     uint8_t buffer[128+2*256];
  378.     if( i_socks_version != 4 && i_socks_version != 5 )
  379.     {
  380.         msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
  381.         i_socks_version = 5;
  382.     }
  383.     if( i_socks_version == 5 &&
  384.         SocksNegotiate( p_obj, fd, i_socks_version,
  385.                         psz_user, psz_passwd ) )
  386.         return VLC_EGENERIC;
  387.     if( i_socks_version == 4 )
  388.     {
  389.         struct addrinfo hints, *p_res;
  390.         /* v4 only support ipv4 */
  391.         memset (&hints, 0, sizeof (hints));
  392.         hints.ai_family = AF_INET;
  393.         if( vlc_getaddrinfo( p_obj, psz_host, 0, &hints, &p_res ) )
  394.             return VLC_EGENERIC;
  395.         buffer[0] = i_socks_version;
  396.         buffer[1] = 0x01;               /* CONNECT */
  397.         SetWBE( &buffer[2], i_port );   /* Port */
  398.         memcpy( &buffer[4],             /* Address */
  399.                 &((struct sockaddr_in *)(p_res->ai_addr))->sin_addr, 4 );
  400.         vlc_freeaddrinfo( p_res );
  401.         buffer[8] = 0;                  /* Empty user id */
  402.         if( net_Write( p_obj, fd, NULL, buffer, 9 ) != 9 )
  403.             return VLC_EGENERIC;
  404.         if( net_Read( p_obj, fd, NULL, buffer, 8, true ) != 8 )
  405.             return VLC_EGENERIC;
  406.         msg_Dbg( p_obj, "socks: v=%d cd=%d",
  407.                  buffer[0], buffer[1] );
  408.         if( buffer[1] != 90 )
  409.             return VLC_EGENERIC;
  410.     }
  411.     else if( i_socks_version == 5 )
  412.     {
  413.         int i_hlen = __MIN(strlen( psz_host ), 255);
  414.         int i_len;
  415.         buffer[0] = i_socks_version;    /* Version */
  416.         buffer[1] = 0x01;               /* Cmd: connect */
  417.         buffer[2] = 0x00;               /* Reserved */
  418.         buffer[3] = 3;                  /* ATYP: for now domainname */
  419.         buffer[4] = i_hlen;
  420.         memcpy( &buffer[5], psz_host, i_hlen );
  421.         SetWBE( &buffer[5+i_hlen], i_port );
  422.         i_len = 5 + i_hlen + 2;
  423.         if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
  424.             return VLC_EGENERIC;
  425.         /* Read the header */
  426.         if( net_Read( p_obj, fd, NULL, buffer, 5, true ) != 5 )
  427.             return VLC_EGENERIC;
  428.         msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
  429.                  buffer[0], buffer[1], buffer[3] );
  430.         if( buffer[1] != 0x00 )
  431.         {
  432.             msg_Err( p_obj, "socks: CONNECT request failed" );
  433.             return VLC_EGENERIC;
  434.         }
  435.         /* Read the remaining bytes */
  436.         if( buffer[3] == 0x01 )
  437.             i_len = 4-1 + 2;
  438.         else if( buffer[3] == 0x03 )
  439.             i_len = buffer[4] + 2;
  440.         else if( buffer[3] == 0x04 )
  441.             i_len = 16-1+2;
  442.         else
  443.             return VLC_EGENERIC;
  444.         if( net_Read( p_obj, fd, NULL, buffer, i_len, true ) != i_len )
  445.             return VLC_EGENERIC;
  446.     }
  447.     return VLC_SUCCESS;
  448. }
  449. void net_ListenClose( int *pi_fd )
  450. {
  451.     if( pi_fd != NULL )
  452.     {
  453.         int *pi;
  454.         for( pi = pi_fd; *pi != -1; pi++ )
  455.             net_Close( *pi );
  456.         free( pi_fd );
  457.     }
  458. }