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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * sap.c : SAP announce handler
  3.  *****************************************************************************
  4.  * Copyright (C) 2002-2004 VideoLAN
  5.  * $Id: sap.c 9201 2004-11-06 16:51:46Z yoann $
  6.  *
  7.  * Authors: Cl閙ent Stenac <zorglub@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>                                                /* free() */
  27. #include <stdio.h>                                              /* sprintf() */
  28. #include <string.h>                                            /* strerror() */
  29. #include <vlc/vlc.h>
  30. #include <vlc/sout.h>
  31. #include <network.h>
  32. #define SAP_IPV4_ADDR "224.2.127.254" /* Standard port and address for SAP */
  33. #define SAP_PORT 9875
  34. #define SAP_IPV6_ADDR_1 "FF0"
  35. #define SAP_IPV6_ADDR_2 "::2:7FFE"
  36. #define DEFAULT_IPV6_SCOPE '8'
  37. #define DEFAULT_PORT "1234"
  38. #undef EXTRA_DEBUG
  39. /*****************************************************************************
  40.  * Local prototypes
  41.  *****************************************************************************/
  42. static void RunThread( vlc_object_t *p_this);
  43. static int CalculateRate( sap_handler_t *p_sap, sap_address_t *p_address );
  44. static int SDPGenerate( sap_handler_t *p_sap, session_descriptor_t *p_session );
  45. static int announce_SendSAPAnnounce( sap_handler_t *p_sap,
  46.                                      sap_session_t *p_session );
  47. static int announce_SAPAnnounceAdd( sap_handler_t *p_sap,
  48.                              session_descriptor_t *p_session,
  49.                              announce_method_t *p_method );
  50. static int announce_SAPAnnounceDel( sap_handler_t *p_sap,
  51.                              session_descriptor_t *p_session );
  52. #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
  53. /**
  54.  * Create the SAP handler
  55.  *
  56.  * param p_announce the parent announce_handler
  57.  * return the newly created SAP handler or NULL on error
  58.  */
  59. sap_handler_t *announce_SAPHandlerCreate( announce_handler_t *p_announce )
  60. {
  61.     sap_handler_t *p_sap;
  62.     p_sap = vlc_object_create( p_announce, sizeof( sap_handler_t ) );
  63.     if( !p_sap )
  64.     {
  65.         msg_Err( p_announce, "out of memory" );
  66.         return NULL;
  67.     }
  68.     vlc_mutex_init( p_sap, &p_sap->object_lock );
  69.     p_sap->pf_add = announce_SAPAnnounceAdd;
  70.     p_sap->pf_del = announce_SAPAnnounceDel;
  71.     p_sap->i_sessions = 0;
  72.     p_sap->i_addresses = 0;
  73.     p_sap->i_current_session = 0;
  74.     p_sap->b_control = config_GetInt( p_sap, "sap-flow-control");
  75.     if( vlc_thread_create( p_sap, "sap handler", RunThread,
  76.                        VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
  77.     {
  78.         msg_Dbg( p_announce, "Unable to spawn SAP handler thread");
  79.         free( p_sap );
  80.         return NULL;
  81.     };
  82.     msg_Dbg( p_announce, "thread created, %i sessions", p_sap->i_sessions);
  83.     return p_sap;
  84. }
  85. /**
  86.  *  Destroy the SAP handler
  87.  *  param p_this the SAP Handler to destroy
  88.  *  return nothing
  89.  */
  90. void announce_SAPHandlerDestroy( sap_handler_t *p_sap )
  91. {
  92.     int i;
  93.     vlc_mutex_destroy( &p_sap->object_lock );
  94.     /* Free the remaining sessions */
  95.     for( i = 0 ; i< p_sap->i_sessions ; i++)
  96.     {
  97.         sap_session_t *p_session = p_sap->pp_sessions[i];
  98.         FREE( p_session->psz_sdp );
  99.         FREE( p_session->psz_data );
  100.         REMOVE_ELEM( p_sap->pp_sessions, p_sap->i_sessions , i );
  101.         FREE( p_session );
  102.     }
  103.     /* Free the remaining addresses */
  104.     for( i = 0 ; i< p_sap->i_addresses ; i++)
  105.     {
  106.         sap_address_t *p_address = p_sap->pp_addresses[i];
  107.         FREE( p_address->psz_address );
  108.         if( p_address->i_rfd > -1 )
  109.         {
  110.             net_Close( p_address->i_rfd );
  111.         }
  112.         if( p_address->i_wfd > -1 && p_sap->b_control )
  113.         {
  114.             net_Close( p_address->i_wfd );
  115.         }
  116.         REMOVE_ELEM( p_sap->pp_addresses, p_sap->i_addresses, i );
  117.         FREE( p_address );
  118.     }
  119.     /* Free the structure */
  120.     vlc_object_destroy( p_sap );
  121. }
  122. /**
  123.  * main SAP handler thread
  124.  * param p_this the SAP Handler object
  125.  * return nothing
  126.  */
  127. static void RunThread( vlc_object_t *p_this)
  128. {
  129.     sap_handler_t *p_sap = (sap_handler_t*)p_this;
  130.     sap_session_t *p_session;
  131.     while( !p_sap->b_die )
  132.     {
  133.         int i;
  134.         /* If needed, get the rate info */
  135.         if( p_sap->b_control == VLC_TRUE )
  136.         {
  137.             for( i = 0 ; i< p_sap->i_addresses ; i++)
  138.             {
  139.                 if( p_sap->pp_addresses[i]->b_enabled == VLC_TRUE )
  140.                 {
  141.                     CalculateRate( p_sap, p_sap->pp_addresses[i] );
  142.                 }
  143.             }
  144.         }
  145.         /* Find the session to announce */
  146.         vlc_mutex_lock( &p_sap->object_lock );
  147.         if( p_sap->i_sessions > p_sap->i_current_session + 1)
  148.         {
  149.             p_sap->i_current_session++;
  150.         }
  151.         else if( p_sap->i_sessions > 0)
  152.         {
  153.             p_sap->i_current_session = 0;
  154.         }
  155.         else
  156.         {
  157.             vlc_mutex_unlock( &p_sap->object_lock );
  158.             msleep( SAP_IDLE );
  159.             continue;
  160.         }
  161.         p_session = p_sap->pp_sessions[p_sap->i_current_session];
  162.         vlc_mutex_unlock( &p_sap->object_lock );
  163.         /* And announce it */
  164.         if( p_session->p_address->b_enabled == VLC_TRUE &&
  165.             p_session->p_address->b_ready == VLC_TRUE )
  166.         {
  167.             announce_SendSAPAnnounce( p_sap, p_session );
  168.         }
  169.         msleep( SAP_IDLE );
  170.     }
  171. }
  172. /* Add a SAP announce */
  173. static int announce_SAPAnnounceAdd( sap_handler_t *p_sap,
  174.                              session_descriptor_t *p_session,
  175.                              announce_method_t *p_method )
  176. {
  177.     int i;
  178.     char *psz_type = "application/sdp";
  179.     int i_header_size;
  180.     char *psz_head;
  181.     vlc_bool_t b_found = VLC_FALSE;
  182.     sap_session_t *p_sap_session;
  183.     mtime_t i_hash;
  184.     vlc_mutex_lock( &p_sap->object_lock );
  185.     /* If needed, build the SDP */
  186.     if( !p_session->psz_sdp )
  187.     {
  188.         if ( SDPGenerate( p_sap, p_session ) != VLC_SUCCESS )
  189.         {
  190.             vlc_mutex_unlock( &p_sap->object_lock );
  191.             return VLC_EGENERIC;
  192.         }
  193.     }
  194.     if( !p_method->psz_address )
  195.     {
  196.         if( p_method->i_ip_version == 6 )
  197.         {
  198.             char sz_scope;
  199.             if( p_method->psz_ipv6_scope != NULL )
  200.             {
  201.                 sz_scope = *p_method->psz_ipv6_scope;
  202.             }
  203.             else
  204.             {
  205.                 sz_scope = DEFAULT_IPV6_SCOPE;
  206.             }
  207.             p_method->psz_address = (char*)malloc( 30*sizeof(char ));
  208.             sprintf( p_method->psz_address, "%s%c%s",
  209.                             SAP_IPV6_ADDR_1, sz_scope, SAP_IPV6_ADDR_2 );
  210.         }
  211.         else
  212.         {
  213.             /* IPv4 */
  214.             p_method->psz_address = (char*)malloc( 15*sizeof(char) );
  215.             snprintf(p_method->psz_address, 15, SAP_IPV4_ADDR );
  216.         }
  217.     }
  218.     msg_Dbg( p_sap, "using SAP address: %s",p_method->psz_address);
  219.     /* XXX: Check for dupes */
  220.     p_sap_session = (sap_session_t*)malloc(sizeof(sap_session_t));
  221.     p_sap_session->psz_sdp = strdup( p_session->psz_sdp );
  222.     p_sap_session->i_last = 0;
  223.     /* Add the address to the buffer */
  224.     for( i = 0; i< p_sap->i_addresses; i++)
  225.     {
  226.         if( !strcmp( p_method->psz_address,
  227.              p_sap->pp_addresses[i]->psz_address ) )
  228.         {
  229.             p_sap_session->p_address = p_sap->pp_addresses[i];
  230.             b_found = VLC_TRUE;
  231.             break;
  232.         }
  233.     }
  234.     if( b_found == VLC_FALSE )
  235.     {
  236.         sap_address_t *p_address = (sap_address_t *)
  237.                                     malloc( sizeof(sap_address_t) );
  238.         if( !p_address )
  239.         {
  240.             msg_Err( p_sap, "out of memory" );
  241.             return VLC_ENOMEM;
  242.         }
  243.         p_address->psz_address = strdup( p_method->psz_address );
  244.         p_address->i_ip_version = p_method->i_ip_version;
  245.         p_address->i_port  =  9875;
  246.         p_address->i_wfd = net_OpenUDP( p_sap, "", 0,
  247.                                         p_address->psz_address,
  248.                                         p_address->i_port );
  249.         if( p_sap->b_control == VLC_TRUE )
  250.         {
  251.             p_address->i_rfd = net_OpenUDP( p_sap, p_method->psz_address,
  252.                                             p_address->i_port,
  253.                                             "", 0 );
  254.             p_address->i_buff = 0;
  255.             p_address->b_enabled = VLC_TRUE;
  256.             p_address->b_ready = VLC_FALSE;
  257.             p_address->i_limit = 10000; /* 10000 bps */
  258.             p_address->t1 = 0;
  259.         }
  260.         else
  261.         {
  262.             p_address->b_enabled = VLC_TRUE;
  263.             p_address->b_ready = VLC_TRUE;
  264.             p_address->i_interval = config_GetInt( p_sap,"sap-interval");
  265.         }
  266.         if( p_address->i_wfd == -1 || (p_address->i_rfd == -1
  267.                                         && p_sap->b_control ) )
  268.         {
  269.             msg_Warn( p_sap, "disabling address" );
  270.             p_address->b_enabled = VLC_FALSE;
  271.         }
  272.         INSERT_ELEM( p_sap->pp_addresses,
  273.                      p_sap->i_addresses,
  274.                      p_sap->i_addresses,
  275.                      p_address );
  276.         p_sap_session->p_address = p_address;
  277.     }
  278.     /* Build the SAP Headers */
  279.     i_header_size = ( p_method->i_ip_version == 6 ? 20 : 8 ) + strlen( psz_type ) + 1;
  280.     psz_head = (char *) malloc( i_header_size * sizeof( char ) );
  281.     if( ! psz_head )
  282.     {
  283.         msg_Err( p_sap, "out of memory" );
  284.         return VLC_ENOMEM;
  285.     }
  286.     psz_head[0] = 0x20; /* Means SAPv1, IPv4, not encrypted, not compressed */
  287.     psz_head[1] = 0x00; /* No authentification length */
  288.     i_hash = mdate();
  289.     psz_head[2] = (i_hash & 0xFF00) >> 8; /* Msg id hash */
  290.     psz_head[3] = (i_hash & 0xFF);        /* Msg id hash 2 */
  291.     if( p_method->i_ip_version == 6 )
  292.     {
  293.         /* in_addr_t ip_server = inet_addr( ip ); */
  294.         psz_head[0] |= 0x10; /* Set IPv6 */
  295.         psz_head[4] = 0x01; /* Source IP  FIXME: we should get the real address */
  296.         psz_head[5] = 0x02; /* idem */
  297.         psz_head[6] = 0x03; /* idem */
  298.         psz_head[7] = 0x04; /* idem */
  299.         psz_head[8] = 0x01; /* Source IP  FIXME: we should get the real address */
  300.         psz_head[9] = 0x02; /* idem */
  301.         psz_head[10] = 0x03; /* idem */
  302.         psz_head[11] = 0x04; /* idem */
  303.         psz_head[12] = 0x01; /* Source IP  FIXME: we should get the real address */
  304.         psz_head[13] = 0x02; /* idem */
  305.         psz_head[14] = 0x03; /* idem */
  306.         psz_head[15] = 0x04; /* idem */
  307.         psz_head[16] = 0x01; /* Source IP  FIXME: we should get the real address */
  308.         psz_head[17] = 0x02; /* idem */
  309.         psz_head[18] = 0x03; /* idem */
  310.         psz_head[19] = 0x04; /* idem */
  311.         strncpy( psz_head + 20, psz_type, 15 );
  312.     }
  313.     else
  314.     {
  315.         /* in_addr_t ip_server = inet_addr( ip) */
  316.         /* Source IP  FIXME: we should get the real address */
  317.         psz_head[4] = 0x01; /* ip_server */
  318.         psz_head[5] = 0x02; /* ip_server>>8 */
  319.         psz_head[6] = 0x03; /* ip_server>>16 */
  320.         psz_head[7] = 0x04; /* ip_server>>24 */
  321.         strncpy( psz_head + 8, psz_type, 15 );
  322.     }
  323.     psz_head[ i_header_size-1 ] = '';
  324.     p_sap_session->i_length = i_header_size + strlen( p_sap_session->psz_sdp);
  325.     p_sap_session->psz_data = (char *)malloc( sizeof(char)*
  326.                                               p_sap_session->i_length );
  327.     /* Build the final message */
  328.     memcpy( p_sap_session->psz_data, psz_head, i_header_size );
  329.     memcpy( p_sap_session->psz_data+i_header_size, p_sap_session->psz_sdp,
  330.             strlen( p_sap_session->psz_sdp) );
  331.     free( psz_head );
  332.     /* Enqueue the announce */
  333.     INSERT_ELEM( p_sap->pp_sessions,
  334.                  p_sap->i_sessions,
  335.                  p_sap->i_sessions,
  336.                  p_sap_session );
  337.     msg_Dbg( p_sap,"Addresses: %i  Sessions: %i",
  338.                    p_sap->i_addresses,p_sap->i_sessions);
  339.     /* Remember the SAP session for later deletion */
  340.     p_session->p_sap = p_sap_session;
  341.     vlc_mutex_unlock( &p_sap->object_lock );
  342.     return VLC_SUCCESS;
  343. }
  344. /* Remove a SAP Announce */
  345. static int announce_SAPAnnounceDel( sap_handler_t *p_sap,
  346.                              session_descriptor_t *p_session )
  347. {
  348.     int i;
  349.     vlc_mutex_lock( &p_sap->object_lock );
  350.     msg_Dbg( p_sap,"removing SAP announce %p",p_session->p_sap);
  351.     /* Dequeue the announce */
  352.     for( i = 0; i< p_sap->i_sessions; i++)
  353.     {
  354.         if( p_session->p_sap == p_sap->pp_sessions[i] )
  355.         {
  356.             REMOVE_ELEM( p_sap->pp_sessions,
  357.                          p_sap->i_sessions,
  358.                          i );
  359.             break;
  360.         }
  361.     }
  362.     /* XXX: Dequeue the address too if it is not used anymore
  363.      * TODO: - address refcount
  364.              - send a SAP deletion packet */
  365.     msg_Dbg( p_sap,"%i announces remaining", p_sap->i_sessions );
  366.     vlc_mutex_unlock( &p_sap->object_lock );
  367.     return VLC_SUCCESS;
  368. }
  369. static int announce_SendSAPAnnounce( sap_handler_t *p_sap,
  370.                                      sap_session_t *p_session )
  371. {
  372.     int i_ret;
  373.     /* This announce has never been sent yet */
  374.     if( p_session->i_last == 0 )
  375.     {
  376.         p_session->i_next = mdate()+ p_session->p_address->i_interval*1000000;
  377.         p_session->i_last = 1;
  378.         return VLC_SUCCESS;
  379.     }
  380.     if( p_session->i_next < mdate() )
  381.     {
  382. #ifdef EXTRA_DEBUG
  383.         msg_Dbg( p_sap, "Sending announce");
  384. #endif
  385.         i_ret = net_Write( p_sap, p_session->p_address->i_wfd,
  386.                            p_session->psz_data,
  387.                            p_session->i_length );
  388.         if( i_ret  != p_session->i_length )
  389.         {
  390.             msg_Warn( p_sap, "SAP send failed on address %s (%i %i)",
  391.                    p_session->p_address->psz_address,
  392.                    i_ret, p_session->i_length );
  393.         }
  394.         p_session->i_last = p_session->i_next;
  395.         p_session->i_next = p_session->i_last
  396.                             + p_session->p_address->i_interval*1000000;
  397.     }
  398.     else
  399.     {
  400.         return VLC_SUCCESS;
  401.     }
  402.     return VLC_SUCCESS;
  403. }
  404. static int SDPGenerate( sap_handler_t *p_sap, session_descriptor_t *p_session )
  405. {
  406.     int64_t i_sdp_id = mdate();
  407.     int     i_sdp_version = 1 + p_sap->i_sessions + (rand()&0xfff);
  408.     /* see the lists in modules/stream_out/rtp.c for compliance stuff */
  409.     p_session->psz_sdp = (char *)malloc(
  410.                             sizeof("v=0rn"
  411.                                    "o=- 45383436098 45398  IN IP4 127.0.0.1rn" /* FIXME */
  412.                                    "s=rn"
  413.                                    "t=0 0rn"
  414.                                    "c=IN IP4 /rn"
  415.                                    "m=video  udprn"
  416.                                    "a=tool:"PACKAGE_STRING"rn"
  417.                                    "a=type:broadcastrn")
  418.                            + strlen( p_session->psz_name )
  419.                            + strlen( p_session->psz_uri ) + 300
  420.                            + ( p_session->psz_group ?
  421.                                  strlen( p_session->psz_group ) : 0 ) );
  422.     if( !p_session->psz_sdp )
  423.     {
  424.         msg_Err( p_sap, "out of memory" );
  425.         return VLC_ENOMEM;
  426.     }
  427.     sprintf( p_session->psz_sdp,
  428.                             "v=0rn"
  429.                             "o=- "I64Fd" %d IN IP4 127.0.0.1rn"
  430.                             "s=%srn"
  431.                             "t=0 0rn"
  432.                             "c=IN IP4 %s/%drn"
  433.                             "m=video %d udp %drn"
  434.                             "a=tool:"PACKAGE_STRING"rn"
  435.                             "a=type:broadcastrn",
  436.                             i_sdp_id, i_sdp_version,
  437.                             p_session->psz_name,
  438.                             p_session->psz_uri, p_session->i_ttl,
  439.                             p_session->i_port, p_session->i_payload );
  440.     if( p_session->psz_group )
  441.     {
  442.         sprintf( p_session->psz_sdp, "%sa=x-plgroup:%srn",
  443.                                      p_session->psz_sdp,
  444.                                      p_session->psz_group );
  445.     }
  446.     msg_Dbg( p_sap, "Generated SDP (%i bytes):n%s", strlen(p_session->psz_sdp),
  447.                     p_session->psz_sdp );
  448.     return VLC_SUCCESS;
  449. }
  450. static int CalculateRate( sap_handler_t *p_sap, sap_address_t *p_address )
  451. {
  452.     int i_read;
  453.     char buffer[SAP_MAX_BUFFER];
  454.     int i_tot = 0;
  455.     mtime_t i_temp;
  456.     int i_rate;
  457.     if( p_address->t1 == 0 )
  458.     {
  459.         p_address->t1 = mdate();
  460.         return VLC_SUCCESS;
  461.     }
  462.     do
  463.     {
  464.         /* Might be too slow if we have huge data */
  465.         i_read = net_ReadNonBlock( p_sap, p_address->i_rfd, buffer,
  466.                                    SAP_MAX_BUFFER, 0 );
  467.         i_tot += i_read;
  468.     } while( i_read > 0 && i_tot < SAP_MAX_BUFFER );
  469.     i_temp = mdate();
  470.     /* We calculate the rate every 5 seconds */
  471.     if( i_temp - p_address->t1 < 5000000 )
  472.     {
  473.         p_address->i_buff += i_tot;
  474.         return VLC_SUCCESS;
  475.     }
  476.     /* Bits/second */
  477.     i_rate = (int)(8*1000000*((mtime_t)p_address->i_buff + (mtime_t)i_tot ) /
  478.                         (i_temp - p_address->t1 ));
  479.     p_address->i_limit = 10000;
  480.     p_address->i_interval = ((1000*i_rate / p_address->i_limit) *
  481.                             (MAX_INTERVAL - MIN_INTERVAL))/1000 + MIN_INTERVAL;
  482.     if( p_address->i_interval > MAX_INTERVAL || p_address->i_interval < 0 )
  483.     {
  484.         p_address->i_interval = MAX_INTERVAL;
  485.     }
  486. #ifdef EXTRA_DEBUG
  487.     msg_Dbg( p_sap,"%s:%i : Rate=%i, Interval = %i s",
  488.                     p_address->psz_address,p_address->i_port,
  489.                     i_rate,
  490.                     p_address->i_interval );
  491. #endif
  492.     p_address->b_ready = VLC_TRUE;
  493.     p_address->t1 = i_temp;
  494.     p_address->i_buff = 0;
  495.     return VLC_SUCCESS;
  496. }