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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * net.c:
  3.  *****************************************************************************
  4.  * Copyright (C) 2004 VideoLAN
  5.  * $Id: net.c 9170 2004-11-06 11:14:00Z zorglub $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #include <stdlib.h>
  27. #include <vlc/vlc.h>
  28. #include <errno.h>
  29. #ifdef HAVE_FCNTL_H
  30. #   include <fcntl.h>
  31. #endif
  32. #ifdef HAVE_SYS_TIME_H
  33. #    include <sys/time.h>
  34. #endif
  35. #if defined( UNDER_CE )
  36. #   include <winsock.h>
  37. #elif defined( WIN32 )
  38. #   include <winsock2.h>
  39. #   include <ws2tcpip.h>
  40. #   ifndef IN_MULTICAST
  41. #       define IN_MULTICAST(a) IN_CLASSD(a)
  42. #   endif
  43. #else
  44. #   include <sys/socket.h>
  45. #endif
  46. #ifdef HAVE_UNISTD_H
  47. #   include <unistd.h>
  48. #elif defined( WIN32 ) && !defined( UNDER_CE )
  49. #   include <io.h>
  50. #endif
  51. #include "network.h"
  52. /*****************************************************************************
  53.  * __net_OpenTCP:
  54.  *****************************************************************************
  55.  * Open a TCP connection and return a handle
  56.  *****************************************************************************/
  57. int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
  58. {
  59.     vlc_value_t      val;
  60.     void            *private;
  61.     char            *psz_network = "";
  62.     network_socket_t sock;
  63.     module_t         *p_network;
  64.     /* Check if we have force ipv4 or ipv6 */
  65.     var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  66.     var_Get( p_this, "ipv4", &val );
  67.     if( val.b_bool )
  68.     {
  69.         psz_network = "ipv4";
  70.     }
  71.     var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  72.     var_Get( p_this, "ipv6", &val );
  73.     if( val.b_bool )
  74.     {
  75.         psz_network = "ipv6";
  76.     }
  77.     /* Prepare the network_socket_t structure */
  78.     sock.i_type = NETWORK_TCP;
  79.     sock.psz_bind_addr   = "";
  80.     sock.i_bind_port     = 0;
  81.     sock.psz_server_addr = (char *)psz_host;
  82.     sock.i_server_port   = i_port;
  83.     sock.i_ttl           = 0;
  84.     msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_host, i_port );
  85.     private = p_this->p_private;
  86.     p_this->p_private = (void*)&sock;
  87.     if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
  88.     {
  89.         msg_Dbg( p_this, "net: connection to '%s:%d' failed",
  90.                  psz_host, i_port );
  91.         return -1;
  92.     }
  93.     module_Unneed( p_this, p_network );
  94.     p_this->p_private = private;
  95.     return sock.i_handle;
  96. }
  97. /*****************************************************************************
  98.  * __net_ListenTCP:
  99.  *****************************************************************************
  100.  * Open a TCP listening socket and return it
  101.  *****************************************************************************/
  102. int __net_ListenTCP( vlc_object_t *p_this, char *psz_host, int i_port )
  103. {
  104.     vlc_value_t      val;
  105.     void            *private;
  106.     char            *psz_network = "";
  107.     network_socket_t sock;
  108.     module_t         *p_network;
  109.     /* Check if we have force ipv4 or ipv6 */
  110.     var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  111.     var_Get( p_this, "ipv4", &val );
  112.     if( val.b_bool )
  113.     {
  114.         psz_network = "ipv4";
  115.     }
  116.     var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  117.     var_Get( p_this, "ipv6", &val );
  118.     if( val.b_bool )
  119.     {
  120.         psz_network = "ipv6";
  121.     }
  122.     /* Prepare the network_socket_t structure */
  123.     sock.i_type = NETWORK_TCP_PASSIVE;
  124.     sock.psz_bind_addr   = "";
  125.     sock.i_bind_port     = 0;
  126.     sock.psz_server_addr = psz_host;
  127.     sock.i_server_port   = i_port;
  128.     sock.i_ttl           = 0;
  129.     msg_Dbg( p_this, "net: listening to '%s:%d'", psz_host, i_port );
  130.     private = p_this->p_private;
  131.     p_this->p_private = (void*)&sock;
  132.     if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
  133.     {
  134.         msg_Dbg( p_this, "net: listening to '%s:%d' failed",
  135.                  psz_host, i_port );
  136.         return -1;
  137.     }
  138.     module_Unneed( p_this, p_network );
  139.     p_this->p_private = private;
  140.     return sock.i_handle;
  141. }
  142. /*****************************************************************************
  143.  * __net_Accept:
  144.  *****************************************************************************
  145.  * Accept a connection on a listening socket and return it
  146.  *****************************************************************************/
  147. int __net_Accept( vlc_object_t *p_this, int fd, mtime_t i_wait )
  148. {
  149.     vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
  150.     struct timeval timeout;
  151.     fd_set fds_r, fds_e;
  152.     int i_ret;
  153.     while( p_this->b_die == b_die )
  154.     {
  155.         /* Initialize file descriptor set */
  156.         FD_ZERO( &fds_r );
  157.         FD_SET( fd, &fds_r );
  158.         FD_ZERO( &fds_e );
  159.         FD_SET( fd, &fds_e );
  160.         timeout.tv_sec = 0;
  161.         timeout.tv_usec = b_block ? 500000 : i_wait;
  162.         i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
  163.         if( (i_ret < 0 && errno == EINTR) || i_ret == 0 )
  164.         {
  165.             if( b_block ) continue;
  166.             else return -1;
  167.         }
  168.         else if( i_ret < 0 )
  169.         {
  170. #if defined(WIN32) || defined(UNDER_CE)
  171.             msg_Err( p_this, "network select error (%i)", WSAGetLastError() );
  172. #else
  173.             msg_Err( p_this, "network select error (%s)", strerror(errno) );
  174. #endif
  175.             return -1;
  176.         }
  177.         if( ( i_ret = accept( fd, 0, 0 ) ) <= 0 )
  178.         {
  179. #if defined(WIN32) || defined(UNDER_CE)
  180.             msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
  181. #else
  182.             msg_Err( p_this, "accept failed (%s)", strerror(errno) );
  183. #endif
  184.             return -1;
  185.         }
  186.         return i_ret;
  187.     }
  188.     return -1;
  189. }
  190. /*****************************************************************************
  191.  * __net_OpenUDP:
  192.  *****************************************************************************
  193.  * Open a UDP connection and return a handle
  194.  *****************************************************************************/
  195. int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int i_bind,
  196.                    char *psz_server, int i_server )
  197. {
  198.     vlc_value_t      val;
  199.     void            *private;
  200.     char            *psz_network = "";
  201.     network_socket_t sock;
  202.     module_t         *p_network;
  203.     /* Check if we have force ipv4 or ipv6 */
  204.     var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  205.     var_Get( p_this, "ipv4", &val );
  206.     if( val.b_bool )
  207.     {
  208.         psz_network = "ipv4";
  209.     }
  210.     var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  211.     var_Get( p_this, "ipv6", &val );
  212.     if( val.b_bool )
  213.     {
  214.         psz_network = "ipv6";
  215.     }
  216.     if( psz_server == NULL ) psz_server = "";
  217.     if( psz_bind   == NULL ) psz_bind   = "";
  218.     /* Prepare the network_socket_t structure */
  219.     sock.i_type = NETWORK_UDP;
  220.     sock.psz_bind_addr   = psz_bind;
  221.     sock.i_bind_port     = i_bind;
  222.     sock.psz_server_addr = psz_server;
  223.     sock.i_server_port   = i_server;
  224.     sock.i_ttl           = 0;
  225.     msg_Dbg( p_this, "net: connecting to '%s:%d@%s:%d'",
  226.              psz_server, i_server, psz_bind, i_bind );
  227.     private = p_this->p_private;
  228.     p_this->p_private = (void*)&sock;
  229.     if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
  230.     {
  231.         msg_Dbg( p_this, "net: connection to '%s:%d@%s:%d' failed",
  232.                  psz_server, i_server, psz_bind, i_bind );
  233.         return -1;
  234.     }
  235.     module_Unneed( p_this, p_network );
  236.     p_this->p_private = private;
  237.     return sock.i_handle;
  238. }
  239. /*****************************************************************************
  240.  * __net_Close:
  241.  *****************************************************************************
  242.  * Close a network handle
  243.  *****************************************************************************/
  244. void net_Close( int fd )
  245. {
  246. #ifdef UNDER_CE
  247.     CloseHandle( (HANDLE)fd );
  248. #elif defined( WIN32 )
  249.     closesocket( fd );
  250. #else
  251.     close( fd );
  252. #endif
  253. }
  254. /*****************************************************************************
  255.  * __net_Read:
  256.  *****************************************************************************
  257.  * Read from a network socket
  258.  * If b_rety is true, then we repeat until we have read the right amount of
  259.  * data
  260.  *****************************************************************************/
  261. int __net_Read( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data,
  262.                 vlc_bool_t b_retry )
  263. {
  264.     struct timeval  timeout;
  265.     fd_set          fds_r, fds_e;
  266.     int             i_recv;
  267.     int             i_total = 0;
  268.     int             i_ret;
  269.     vlc_bool_t      b_die = p_this->b_die;
  270.     while( i_data > 0 )
  271.     {
  272.         do
  273.         {
  274.             if( p_this->b_die != b_die )
  275.             {
  276.                 return 0;
  277.             }
  278.             /* Initialize file descriptor set */
  279.             FD_ZERO( &fds_r );
  280.             FD_SET( fd, &fds_r );
  281.             FD_ZERO( &fds_e );
  282.             FD_SET( fd, &fds_e );
  283.             /* We'll wait 0.5 second if nothing happens */
  284.             timeout.tv_sec = 0;
  285.             timeout.tv_usec = 500000;
  286.         } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
  287.                  || ( i_ret < 0 && errno == EINTR ) );
  288.         if( i_ret < 0 )
  289.         {
  290. #if defined(WIN32) || defined(UNDER_CE)
  291.             msg_Err( p_this, "network select error" );
  292. #else
  293.             msg_Err( p_this, "network select error (%s)", strerror(errno) );
  294. #endif
  295.             return i_total > 0 ? i_total : -1;
  296.         }
  297.         if( ( i_recv = recv( fd, p_data, i_data, 0 ) ) < 0 )
  298.         {
  299. #if defined(WIN32) || defined(UNDER_CE)
  300.             /* For udp only */
  301.             /* On win32 recv() will fail if the datagram doesn't fit inside
  302.              * the passed buffer, even though the buffer will be filled with
  303.              * the first part of the datagram. */
  304.             if( WSAGetLastError() == WSAEMSGSIZE )
  305.             {
  306.                 msg_Err( p_this, "recv() failed. "
  307.                          "Increase the mtu size (--mtu option)" );
  308.                 i_total += i_data;
  309.             }
  310.             else
  311.                 msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
  312. #else
  313.             msg_Err( p_this, "recv failed (%s)", strerror(errno) );
  314. #endif
  315.             return i_total > 0 ? i_total : -1;
  316.         }
  317.         else if( i_recv == 0 )
  318.         {
  319.             /* Connection closed */
  320.             b_retry = VLC_FALSE;
  321.         }
  322.         p_data += i_recv;
  323.         i_data -= i_recv;
  324.         i_total+= i_recv;
  325.         if( !b_retry )
  326.         {
  327.             break;
  328.         }
  329.     }
  330.     return i_total;
  331. }
  332. /*****************************************************************************
  333.  * __net_ReadNonBlock:
  334.  *****************************************************************************
  335.  * Read from a network socket, non blocking mode (with timeout)
  336.  *****************************************************************************/
  337. int __net_ReadNonBlock( vlc_object_t *p_this, int fd, uint8_t *p_data,
  338.                         int i_data, mtime_t i_wait)
  339. {
  340.     struct timeval  timeout;
  341.     fd_set          fds_r, fds_e;
  342.     int             i_recv;
  343.     int             i_ret;
  344.     /* Initialize file descriptor set */
  345.     FD_ZERO( &fds_r );
  346.     FD_SET( fd, &fds_r );
  347.     FD_ZERO( &fds_e );
  348.     FD_SET( fd, &fds_e );
  349.     timeout.tv_sec = 0;
  350.     timeout.tv_usec = i_wait;
  351.     i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
  352.     if( i_ret < 0 && errno == EINTR )
  353.     {
  354.         return 0;
  355.     }
  356.     else if( i_ret < 0 )
  357.     {
  358. #if defined(WIN32) || defined(UNDER_CE)
  359.         msg_Err( p_this, "network select error" );
  360. #else
  361.         msg_Err( p_this, "network select error (%s)", strerror(errno) );
  362. #endif
  363.         return -1;
  364.     }
  365.     else if( i_ret == 0)
  366.     {
  367.         return 0;
  368.     }
  369.     else
  370.     {
  371. #if !defined(UNDER_CE)
  372.         if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else
  373. #endif
  374.         if( ( i_recv = recv( fd, p_data, i_data, 0 ) ) <= 0 )
  375.         {
  376. #if defined(WIN32) || defined(UNDER_CE)
  377.             /* For udp only */
  378.             /* On win32 recv() will fail if the datagram doesn't fit inside
  379.              * the passed buffer, even though the buffer will be filled with
  380.              * the first part of the datagram. */
  381.             if( WSAGetLastError() == WSAEMSGSIZE )
  382.             {
  383.                 msg_Err( p_this, "recv() failed. "
  384.                          "Increase the mtu size (--mtu option)" );
  385.             }
  386.             else
  387.                 msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
  388. #else
  389.             msg_Err( p_this, "recv failed (%s)", strerror(errno) );
  390. #endif
  391.             return -1;
  392.         }
  393.         return i_recv ? i_recv : -1;  /* !i_recv -> connection closed if tcp */
  394.     }
  395.     /* We will never be here */
  396.     return -1;
  397. }
  398. /*****************************************************************************
  399.  * __net_Select:
  400.  *****************************************************************************
  401.  * Read from several sockets (with timeout). Takes data from the first socket
  402.  * that has some.
  403.  *****************************************************************************/
  404. int __net_Select( vlc_object_t *p_this, int *pi_fd, int i_fd, uint8_t *p_data,
  405.                       int i_data, mtime_t i_wait )
  406. {
  407.     struct timeval  timeout;
  408.     fd_set          fds_r, fds_e;
  409.     int             i_recv;
  410.     int             i_ret;
  411.     int             i;
  412.     int             i_max_fd = 0;
  413.     /* Initialize file descriptor set */
  414.     FD_ZERO( &fds_r );
  415.     FD_ZERO( &fds_e );
  416.     for( i = 0 ; i < i_fd ; i++)
  417.     {
  418.         if( pi_fd[i] > i_max_fd ) i_max_fd = pi_fd[i];
  419.         FD_SET( pi_fd[i], &fds_r );
  420.         FD_SET( pi_fd[i], &fds_e );
  421.     }
  422.     timeout.tv_sec = 0;
  423.     timeout.tv_usec = i_wait;
  424.     i_ret = select( i_max_fd + 1, &fds_r, NULL, &fds_e, &timeout );
  425.     if( i_ret < 0 && errno == EINTR )
  426.     {
  427.         return 0;
  428.     }
  429.     else if( i_ret < 0 )
  430.     {
  431.         msg_Err( p_this, "network select error (%s)", strerror(errno) );
  432.         return -1;
  433.     }
  434.     else if( i_ret == 0 )
  435.     {
  436.         return 0;
  437.     }
  438.     else
  439.     {
  440.         for( i = 0 ; i < i_fd ; i++)
  441.         {
  442.             if( FD_ISSET( pi_fd[i], &fds_r ) )
  443.             {
  444.                 i_recv = recv( pi_fd[i], p_data, i_data, 0 );
  445.                 if( i_recv <= 0 )
  446.                 {
  447. #ifdef WIN32
  448.                     /* For udp only */
  449.                     /* On win32 recv() will fail if the datagram doesn't
  450.                      * fit inside the passed buffer, even though the buffer
  451.                      *  will be filled with the first part of the datagram. */
  452.                     if( WSAGetLastError() == WSAEMSGSIZE )
  453.                     {
  454.                         msg_Err( p_this, "recv() failed. "
  455.                              "Increase the mtu size (--mtu option)" );
  456.                     }
  457.                     else
  458.                         msg_Err( p_this, "recv failed (%i)",
  459.                                         WSAGetLastError() );
  460. #else
  461.                      msg_Err( p_this, "recv failed (%s)", strerror(errno) );
  462. #endif
  463.                     return VLC_EGENERIC;
  464.                 }
  465.                 return i_recv;
  466.             }
  467.         }
  468.     }
  469.     /* We will never be here */
  470.     return -1;
  471. }
  472. /* Write exact amount requested */
  473. int __net_Write( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data )
  474. {
  475.     struct timeval  timeout;
  476.     fd_set          fds_w, fds_e;
  477.     int             i_send;
  478.     int             i_total = 0;
  479.     int             i_ret;
  480.     vlc_bool_t      b_die = p_this->b_die;
  481.     while( i_data > 0 )
  482.     {
  483.         do
  484.         {
  485.             if( p_this->b_die != b_die )
  486.             {
  487.                 return 0;
  488.             }
  489.             /* Initialize file descriptor set */
  490.             FD_ZERO( &fds_w );
  491.             FD_SET( fd, &fds_w );
  492.             FD_ZERO( &fds_e );
  493.             FD_SET( fd, &fds_e );
  494.             /* We'll wait 0.5 second if nothing happens */
  495.             timeout.tv_sec = 0;
  496.             timeout.tv_usec = 500000;
  497.         } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
  498.                  || ( i_ret < 0 && errno == EINTR ) );
  499.         if( i_ret < 0 )
  500.         {
  501. #if defined(WIN32) || defined(UNDER_CE)
  502.             msg_Err( p_this, "network select error" );
  503. #else
  504.             msg_Err( p_this, "network select error (%s)", strerror(errno) );
  505. #endif
  506.             return i_total > 0 ? i_total : -1;
  507.         }
  508.         if( ( i_send = send( fd, p_data, i_data, 0 ) ) < 0 )
  509.         {
  510.             /* XXX With udp for example, it will issue a message if the host
  511.              * isn't listening */
  512.             /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
  513.             return i_total > 0 ? i_total : -1;
  514.         }
  515.         p_data += i_send;
  516.         i_data -= i_send;
  517.         i_total+= i_send;
  518.     }
  519.     return i_total;
  520. }
  521. char *__net_Gets( vlc_object_t *p_this, int fd )
  522. {
  523.     char *psz_line = malloc( 1024 );
  524.     int  i_line = 0;
  525.     int  i_max = 1024;
  526.     for( ;; )
  527.     {
  528.         if( net_Read( p_this, fd, &psz_line[i_line], 1, VLC_TRUE ) != 1 )
  529.         {
  530.             psz_line[i_line] = '';
  531.             break;
  532.         }
  533.         i_line++;
  534.         if( psz_line[i_line-1] == 'n' )
  535.         {
  536.             psz_line[i_line] = '';
  537.             break;
  538.         }
  539.         if( i_line >= i_max - 1 )
  540.         {
  541.             i_max += 1024;
  542.             psz_line = realloc( psz_line, i_max );
  543.         }
  544.     }
  545.     if( i_line <= 0 )
  546.     {
  547.         free( psz_line );
  548.         return NULL;
  549.     }
  550.     while( i_line >= 1 &&
  551.            ( psz_line[i_line-1] == 'n' || psz_line[i_line-1] == 'r' ) )
  552.     {
  553.         i_line--;
  554.         psz_line[i_line] = '';
  555.     }
  556.     return psz_line;
  557. }
  558. int net_Printf( vlc_object_t *p_this, int fd, const char *psz_fmt, ... )
  559. {
  560.     int i_ret;
  561.     va_list args;
  562.     va_start( args, psz_fmt );
  563.     i_ret = net_vaPrintf( p_this, fd, psz_fmt, args );
  564.     va_end( args );
  565.     return i_ret;
  566. }
  567. int __net_vaPrintf( vlc_object_t *p_this, int fd, const char *psz_fmt,
  568.                     va_list args )
  569. {
  570.     char    *psz;
  571.     int     i_size, i_ret;
  572.     vasprintf( &psz, psz_fmt, args );
  573.     i_size = strlen( psz );
  574.     i_ret = __net_Write( p_this, fd, psz, i_size ) < i_size ? -1 : i_size;
  575.     free( psz );
  576.     return i_ret;
  577. }