-
-/****************************************************************************
- * MMSOpen : Open a connection with the server over mmst or mmsu(not yet)
- ****************************************************************************/
-static int MMSOpen( input_thread_t *p_input,
- url_t *p_url,
- int i_proto,
- char *psz_network ) /* "", "ipv4", "ipv6" */
-{
- module_t *p_network;
- access_t *p_access = (access_t*)p_input->p_access_data;
-
- network_socket_t socket_desc;
- int b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0;
-
- var_buffer_t buffer;
- char tmp[4096];
- uint16_t *p;
- int i_server_version;
- int i_tool_version;
- int i_update_player_url;
- int i_encryption_type;
- int i;
- int i_streams;
- int i_first;
-
-
- /* *** Open a TCP connection with server *** */
- msg_Dbg( p_input, "waiting for connection..." );
- socket_desc.i_type = NETWORK_TCP;
- socket_desc.psz_server_addr = p_url->psz_server_addr;
- socket_desc.i_server_port = p_url->i_server_port;
- socket_desc.psz_bind_addr = "";
- socket_desc.i_bind_port = 0;
- p_input->p_private = (void*)&socket_desc;
- if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
- {
- msg_Err( p_input, "failed to open a connection (tcp)" );
- return( -1 );
- }
- module_Unneed( p_input, p_network );
- p_access->socket_tcp.i_handle = socket_desc.i_handle;
- p_input->i_mtu = 0; /*socket_desc.i_mtu;*/
- msg_Dbg( p_input,
- "connection(tcp) with \"%s:%d\" successful",
- p_url->psz_server_addr,
- p_url->i_server_port );
-
- /* *** Bind port if UDP protocol is selected *** */
- if( b_udp )
- {
- if( !p_url->psz_bind_addr || !*p_url->psz_bind_addr )
- {
- struct sockaddr_in name;
- socklen_t i_namelen = sizeof( struct sockaddr_in );
-
- if( getsockname( p_access->socket_tcp.i_handle,
- (struct sockaddr*)&name, &i_namelen ) < 0 )
- {
-
- msg_Err( p_input, "for udp you have to provide bind address (mms://<server_addr>@<bind_addr/<path> (FIXME)" );
-#if defined( UNDER_CE )
- CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
-#elif defined( WIN32 )
- closesocket( p_access->socket_tcp.i_handle );
-#else
- close( p_access->socket_tcp.i_handle );
-#endif
- return( -1 );
- }
- p_access->psz_bind_addr = inet_ntoa( name.sin_addr );
- }
- else
- {
- p_access->psz_bind_addr = strdup( p_url->psz_bind_addr );
- }
- socket_desc.i_type = NETWORK_UDP;
- socket_desc.psz_server_addr = "";
- socket_desc.i_server_port = 0;
- socket_desc.psz_bind_addr = p_access->psz_bind_addr;
- socket_desc.i_bind_port = p_url->i_bind_port;
- p_input->p_private = (void*)&socket_desc;
- if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
- {
- msg_Err( p_input, "failed to open a connection (udp)" );
-#if defined( UNDER_CE )
- CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
-#elif defined( WIN32 )
- closesocket( p_access->socket_tcp.i_handle );
-#else
- close( p_access->socket_tcp.i_handle );
-#endif
- return( -1 );
- }
- module_Unneed( p_input, p_network );
- p_access->socket_udp.i_handle = socket_desc.i_handle;
- p_input->i_mtu = 0;/*socket_desc.i_mtu; FIXME */
-
- }
- else
- {
- p_access->psz_bind_addr = NULL;
- }
-
- /* *** Init context for mms prototcol *** */
- GenerateGuid( &p_access->guid ); /* used to identify client by server */
- msg_Dbg( p_input,
- "generated guid: "GUID_FMT,
- GUID_PRINT( p_access->guid ) );
- p_access->i_command_level = 1; /* updated after 0x1A command */
- p_access->i_seq_num = 0;
- p_access->i_media_packet_id_type = 0x04;
- p_access->i_header_packet_id_type = 0x02;
- p_access->i_proto = i_proto;
- p_access->i_packet_seq_num = 0;
- p_access->p_header = NULL;
- p_access->i_header = 0;
- p_access->p_media = NULL;
- p_access->i_media = 0;
- p_access->i_media_used = 0;
-
- p_access->i_pos = 0;
- p_access->i_buffer_tcp = 0;
- p_access->i_buffer_udp = 0;
- p_access->p_cmd = NULL;
- p_access->i_cmd = 0;
- p_access->i_eos = 0;
-
- /* *** send command 1 : connection request *** */
- var_buffer_initwrite( &buffer, 0 );
- var_buffer_add16( &buffer, 0x001c );
- var_buffer_add16( &buffer, 0x0003 );
- sprintf( tmp,
- "NSPlayer/7.0.0.1956; {"GUID_FMT"}; Host: %s",
- GUID_PRINT( p_access->guid ),
- p_url->psz_server_addr );
- var_buffer_addUTF16( &buffer, tmp );
-
- mms_CommandSend( p_input,
- 0x01, /* connexion request */
- 0x00000000, /* flags, FIXME */
- 0x0004000b, /* ???? */
- buffer.p_data,
- buffer.i_data );
-
- mms_CommandRead( p_input, 0x01, 0 );
- i_server_version = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 32 );
- i_tool_version = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 36 );
- i_update_player_url = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 40 );
- i_encryption_type = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 44 );
- p = (uint16_t*)( p_access->p_cmd + MMS_CMD_HEADERSIZE + 48 );
-#define GETUTF16( psz, size ) \
- { \
- int i; \
- psz = malloc( size + 1); \
- for( i = 0; i < size; i++ ) \
- { \
- psz[i] = p[i]; \
- } \
- psz[size] = '\0'; \
- p += 2 * ( size ); \
- }
- GETUTF16( p_access->psz_server_version, i_server_version );
- GETUTF16( p_access->psz_tool_version, i_tool_version );
- GETUTF16( p_access->psz_update_player_url, i_update_player_url );
- GETUTF16( p_access->psz_encryption_type, i_encryption_type );
-#undef GETUTF16
- msg_Dbg( p_input,
- "0x01 --> server_version:\"%s\" tool_version:\"%s\" update_player_url:\"%s\" encryption_type:\"%s\"",
- p_access->psz_server_version,
- p_access->psz_tool_version,
- p_access->psz_update_player_url,
- p_access->psz_encryption_type );
-
- /* *** should make an 18 command to make data timing *** */
-
- /* *** send command 2 : transport protocol selection *** */
- var_buffer_reinitwrite( &buffer, 0 );
- var_buffer_add32( &buffer, 0x00000000 );
- var_buffer_add32( &buffer, 0x000a0000 );
- var_buffer_add32( &buffer, 0x00000002 );
- if( b_udp )
- {
- sprintf( tmp,
- "\\\\%s\\UDP\\%d",
- p_access->psz_bind_addr,
- p_url->i_bind_port );
- }
- else
- {
- sprintf( tmp, "\\\\127.0.0.1\\TCP\\1242" );
- }
- var_buffer_addUTF16( &buffer, tmp );
- var_buffer_add16( &buffer, '0' );
-
- mms_CommandSend( p_input,
- 0x02, /* connexion request */
- 0x00000000, /* flags, FIXME */
- 0xffffffff, /* ???? */
- buffer.p_data,
- buffer.i_data );
-
- /* *** response from server, should be 0x02 or 0x03 *** */
- mms_CommandRead( p_input, 0x02, 0x03 );
- if( p_access->i_command == 0x03 )
- {
- msg_Err( p_input,
- "%s protocol selection failed", b_udp ? "UDP" : "TCP" );
- var_buffer_free( &buffer );
- MMSClose( p_input );
- return( -1 );
- }
- else if( p_access->i_command != 0x02 )
- {
- msg_Warn( p_input, "received command isn't 0x02 in reponse to 0x02" );
- }
-
- /* *** send command 5 : media file name/path requested *** */
- var_buffer_reinitwrite( &buffer, 0 );
- var_buffer_add64( &buffer, 0 );
- var_buffer_addUTF16( &buffer, p_url->psz_path );
-
- mms_CommandSend( p_input,
- 0x05,
- p_access->i_command_level,
- 0xffffffff,
- buffer.p_data,
- buffer.i_data );
-
- /* *** wait for reponse *** */
- mms_CommandRead( p_input, 0x1a, 0x06 );
-
- /* test if server send 0x1A answer */
- if( p_access->i_command == 0x1A )
- {
- msg_Err( p_input, "id/password requested (not yet supported)" );
- /* FIXME */
- var_buffer_free( &buffer );
- MMSClose( p_input );
- return( -1 );
- }
- if( p_access->i_command != 0x06 )
- {
- msg_Err( p_input,
- "unknown answer (0x%x instead of 0x06)",
- p_access->i_command );
- var_buffer_free( &buffer );
- MMSClose( p_input );
- return( -1 );
- }
-
- /* 1 for file ok, 2 for authen ok */
- switch( GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) )
- {
- case 0x0001:
- msg_Dbg( p_input, "Media file name/path accepted" );
- break;
- case 0x0002:
- msg_Dbg( p_input, "Authentication accepted" );
- break;
- case -1:
- default:
- msg_Err( p_input, "error while asking for file %d",
- GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) );
- var_buffer_free( &buffer );
- MMSClose( p_input );
- return( -1 );
- }
-
- p_access->i_flags_broadcast =
- GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 12 );
- p_access->i_media_length =
- GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 24 );
- p_access->i_packet_length =
- GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 44 );
- p_access->i_packet_count =
- GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 48 );
- p_access->i_max_bit_rate =
- GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 56 );
- p_access->i_header_size =
- GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 60 );
-
- msg_Dbg( p_input,
- "answer 0x06 flags:0x%8.8x media_length:%ds packet_length:%d packet_count:%d max_bit_rate:%d header_size:%d",
- p_access->i_flags_broadcast,
- p_access->i_media_length,
- p_access->i_packet_length,
- p_access->i_packet_count,
- p_access->i_max_bit_rate,
- p_access->i_header_size );
-
- /* XXX XXX dirty hack XXX XXX */
- p_input->i_mtu = 3 * p_access->i_packet_length;
-
- /* *** send command 15 *** */
-
- var_buffer_reinitwrite( &buffer, 0 );
- var_buffer_add32( &buffer, 0 );
- var_buffer_add32( &buffer, 0x8000 );
- var_buffer_add32( &buffer, 0xffffffff );
- var_buffer_add32( &buffer, 0x00 );
- var_buffer_add32( &buffer, 0x00 );
- var_buffer_add32( &buffer, 0x00 );
- var_buffer_add64( &buffer, 0x40ac200000000000 );
- var_buffer_add32( &buffer, p_access->i_header_packet_id_type );
- mms_CommandSend( p_input, 0x15, p_access->i_command_level, 0x00,
- buffer.p_data, buffer.i_data );
-
- /* *** wait for reponse *** */
- mms_CommandRead( p_input, 0x11, 0 );
-
- if( p_access->i_command != 0x11 )
- {
- msg_Err( p_input,
- "unknown answer (0x%x instead of 0x11)",
- p_access->i_command );
- var_buffer_free( &buffer );
- MMSClose( p_input );
- return( -1 );
- }
- /* *** now read header packet *** */
- if( mms_HeaderMediaRead( p_input, MMS_PACKET_HEADER ) < 0 )
- {
- msg_Err( p_input, "cannot receive header" );
- var_buffer_free( &buffer );
- MMSClose( p_input );
- return( -1 );
- }
- /* *** parse header and get stream and their id *** */
- /* get all streams properties,
- *
- * TODO : stream bitrates properties(optional)
- * and bitrate mutual exclusion(optional) */
- asf_HeaderParse( p_access->stream,
- p_access->p_header, p_access->i_header );
- mms_StreamSelect( p_input, p_access->stream );
- /* *** now select stream we want to receive *** */
- /* TODO take care of stream bitrate TODO */
- i_streams = 0;
- i_first = -1;
- var_buffer_reinitwrite( &buffer, 0 );
- /* for now, select first audio and video stream */
- for( i = 1; i < 128; i++ )
- {
-
- if( p_access->stream[i].i_cat != MMS_STREAM_UNKNOWN )
- {
- i_streams++;
- if( i_first != -1 )
- {
- var_buffer_add16( &buffer, 0xffff );
- var_buffer_add16( &buffer, i );
- }
- else
- {
- i_first = i;
- }
- if( p_access->stream[i].i_selected )
- {
- var_buffer_add16( &buffer, 0x0000 );
- msg_Info( p_input,
- "selecting stream[0x%x] %s (%d kb/s)",
- i,
- ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO ) ?
- "audio" : "video" ,
- p_access->stream[i].i_bitrate / 1024);
- }
- else
- {
- var_buffer_add16( &buffer, 0x0002 );
- msg_Info( p_input,
- "ignoring stream[0x%x] %s (%d kb/s)",
- i,
- ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO ) ?
- "audio" : "video" ,
- p_access->stream[i].i_bitrate / 1024);
-
- }
- }
- }
-
- if( i_streams == 0 )
- {
- msg_Err( p_input, "cannot find any stream" );
- var_buffer_free( &buffer );
- MMSClose( p_input );
- return( -1 );
- }
- mms_CommandSend( p_input, 0x33,
- i_streams,
- 0xffff | ( i_first << 16 ),
- buffer.p_data, buffer.i_data );
-
- mms_CommandRead( p_input, 0x21, 0 );
- if( p_access->i_command != 0x21 )
- {
- msg_Err( p_input,
- "unknown answer (0x%x instead of 0x21)",
- p_access->i_command );
- var_buffer_free( &buffer );
- MMSClose( p_input );
- return( -1 );
- }
-
-
- var_buffer_free( &buffer );
-
- msg_Info( p_input, "connection sucessful" );
-
- return( 0 );
-}
-
-/****************************************************************************
- * MMSStart : Start streaming
- ****************************************************************************/
-static int MMSStart ( input_thread_t *p_input, uint32_t i_packet )
-{
- access_t *p_access = (access_t*)p_input->p_access_data;
- var_buffer_t buffer;
-
- /* *** start stream from packet 0 *** */
- var_buffer_initwrite( &buffer, 0 );
- var_buffer_add64( &buffer, 0 ); /* seek point in second */
- var_buffer_add32( &buffer, 0xffffffff );
- var_buffer_add32( &buffer, i_packet ); // begin from start
- var_buffer_add8( &buffer, 0xff ); // stream time limit
- var_buffer_add8( &buffer, 0xff ); // on 3bytes ...
- var_buffer_add8( &buffer, 0xff ); //
- var_buffer_add8( &buffer, 0x00 ); // don't use limit
- var_buffer_add32( &buffer, p_access->i_media_packet_id_type );
-
- mms_CommandSend( p_input, 0x07, p_access->i_command_level, 0x0001ffff,
- buffer.p_data, buffer.i_data );
-
- var_buffer_free( &buffer );
-
- mms_CommandRead( p_input, 0x05, 0 );
-
- if( p_access->i_command != 0x05 )
- {
- msg_Err( p_input,
- "unknown answer (0x%x instead of 0x05)",
- p_access->i_command );
- return( -1 );
- }
- else
- {
- /* get a packet */
- mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
- msg_Dbg( p_input, "Streaming started" );
- return( 0 );
- }
-}
-
-/****************************************************************************
- * MMSStop : Stop streaming
- ****************************************************************************/
-static int MMSStop ( input_thread_t *p_input )
-{
- access_t *p_access = (access_t*)p_input->p_access_data;
-
- /* *** stop stream but keep connection alive *** */
- mms_CommandSend( p_input,
- 0x09,
- p_access->i_command_level,
- 0x001fffff,
- NULL, 0 );
- return( 0 );
-}
-
-/****************************************************************************
- * MMSClose : Close streaming and connection
- ****************************************************************************/
-static int MMSClose ( input_thread_t *p_input )
-{
- access_t *p_access = (access_t*)p_input->p_access_data;
-
- msg_Dbg( p_input, "Connection closed" );
-
- /* *** tell server that we will disconnect *** */
- mms_CommandSend( p_input,
- 0x0d,
- p_access->i_command_level,
- 0x00000001,
- NULL, 0 );
- /* *** close sockets *** */
-#if defined( UNDER_CE )
- CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
-#elif defined( WIN32 )
- closesocket( p_access->socket_tcp.i_handle );
-#else
- close( p_access->socket_tcp.i_handle );
-#endif
-
- if( p_access->i_proto == MMS_PROTO_UDP )
- {
-#if defined( UNDER_CE )
- CloseHandle( (HANDLE)p_access->socket_udp.i_handle );
-#elif defined( WIN32 )
- closesocket( p_access->socket_udp.i_handle );
-#else
- close( p_access->socket_udp.i_handle );
-#endif
- }
-
- FREE( p_access->p_cmd );
- FREE( p_access->p_media );
- FREE( p_access->p_header );
-
- FREE( p_access->psz_server_version );
- FREE( p_access->psz_tool_version );
- FREE( p_access->psz_update_player_url );
- FREE( p_access->psz_encryption_type );
-
- return( 0 );
-}
-
-/*****************************************************************************
- * mms_ParseURL : parse an url string and fill an url_t
- *****************************************************************************/
-static void mms_ParseURL( url_t *p_url, char *psz_url )
-{
- char *psz_parser;
- char *psz_server_port;
-
- p_url->psz_private = strdup( psz_url );
-
- psz_parser = p_url->psz_private;
-
- while( *psz_parser == '/' )
- {
- psz_parser++;
- }
- p_url->psz_server_addr = psz_parser;
-
- while( *psz_parser &&
- *psz_parser != ':' && *psz_parser != '/' && *psz_parser != '@' )
- {
- psz_parser++;
- }
-
- if( *psz_parser == ':' )
- {
- *psz_parser = '\0';
- psz_parser++;
- psz_server_port = psz_parser;
-
- while( *psz_parser && *psz_parser != '/' )
- {
- psz_parser++;
- }
- }
- else
- {
- psz_server_port = "";
- }
-
- if( *psz_parser == '@' )
- {
- char *psz_bind_port;
-
- *psz_parser = '\0';
- psz_parser++;
-
- p_url->psz_bind_addr = psz_parser;
-
- while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' )
- {
- psz_parser++;
- }
-
- if( *psz_parser == ':' )
- {
- *psz_parser = '\0';
- psz_parser++;
- psz_bind_port = psz_parser;
-
- while( *psz_parser && *psz_parser != '/' )
- {
- psz_parser++;
- }
- }
- else
- {
- psz_bind_port = "";
- }
- if( *psz_bind_port )
- {
- p_url->i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
- }
- else
- {
- p_url->i_bind_port = 0;
- }
- }
- else
- {
- p_url->psz_bind_addr = "";
- p_url->i_bind_port = 0;
- }
-
- if( *psz_parser == '/' )
- {
- *psz_parser = '\0';
- psz_parser++;
- p_url->psz_path = psz_parser;
- }
-
- if( *psz_server_port )
- {
- p_url->i_server_port = strtol( psz_server_port, &psz_parser, 10 );
- }
- else
- {
- p_url->i_server_port = 0;
- }
-}
-
-/****************************************************************************
- *
- * MMS specific functions
- *
- ****************************************************************************/
-
-static int mms_CommandSend( input_thread_t *p_input,
- int i_command,
- uint32_t i_prefix1, uint32_t i_prefix2,
- uint8_t *p_data, int i_data )
-{
- var_buffer_t buffer;
-
- access_t *p_access = (access_t*)p_input->p_access_data;
- int i_data_by8;
-
- i_data_by8 = ( i_data + 7 ) / 8;
-
- /* first init uffer */
- var_buffer_initwrite( &buffer, 0 );
-
- var_buffer_add32( &buffer, 0x00000001 ); /* start sequence */
- var_buffer_add32( &buffer, 0xB00BFACE );
- /* size after protocol type */
- var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );
- var_buffer_add32( &buffer, 0x20534d4d ); /* protocol "MMS " */
- var_buffer_add32( &buffer, i_data_by8 + 4 );
- var_buffer_add32( &buffer, p_access->i_seq_num ); p_access->i_seq_num++;
- var_buffer_add64( &buffer, 0 );
- var_buffer_add32( &buffer, i_data_by8 + 2 );
- var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
- var_buffer_add32( &buffer, i_prefix1 ); /* command specific */
- var_buffer_add32( &buffer, i_prefix2 ); /* command specific */
-
- /* specific command data */
- if( p_data && i_data > 0 )
- {
- var_buffer_addmemory( &buffer, p_data, i_data );
- }
-
- /* send it */
- if( send( p_access->socket_tcp.i_handle,
- buffer.p_data,
- buffer.i_data,
- 0 ) == -1 )
- {
- msg_Err( p_input, "failed to send command" );
- return( -1 );
- }
-
- var_buffer_free( &buffer );
- return( 0 );
-}
-
-static int NetFillBuffer( input_thread_t *p_input )
-{
-#ifdef UNDER_CE
- return -1;
-#else
- access_t *p_access = (access_t*)p_input->p_access_data;
- struct timeval timeout;
- fd_set fds;
- int i_ret;
-
- /* FIXME when using udp */
- ssize_t i_tcp, i_udp;
- ssize_t i_tcp_read, i_udp_read;
- int i_handle_max;
-
- /* Initialize file descriptor set */
- FD_ZERO( &fds );
-
- i_tcp = MMS_BUFFER_SIZE/2 - p_access->i_buffer_tcp;
-
- if( p_access->i_proto == MMS_PROTO_UDP )
- {
- i_udp = MMS_BUFFER_SIZE/2 - p_access->i_buffer_udp;
- }
- else
- {
- i_udp = 0; /* there isn't udp socket */
- }
-
- i_handle_max = 0;
- if( i_tcp > 0 )
- {
- FD_SET( p_access->socket_tcp.i_handle, &fds );
- i_handle_max = __MAX( i_handle_max, p_access->socket_tcp.i_handle );
- }
- if( i_udp > 0 )
- {
- FD_SET( p_access->socket_udp.i_handle, &fds );
- i_handle_max = __MAX( i_handle_max, p_access->socket_udp.i_handle );
- }
-
- if( i_handle_max == 0 )
- {
- msg_Warn( p_input, "nothing to read %d:%d", i_tcp, i_udp );
- return( 0 );
- }
- else
- {
-// msg_Warn( p_input, "ask for tcp:%d udp:%d", i_tcp, i_udp );
- }
-
- /* We'll wait 0.5 second if nothing happens */
- timeout.tv_sec = 0;
- timeout.tv_usec = 500000;
-
- /* Find if some data is available */
- i_ret = select( i_handle_max + 1,
- &fds,
- NULL, NULL, &timeout );
-
- if( i_ret == -1 && errno != EINTR )
- {
- msg_Err( p_input, "network select error (%s)", strerror(errno) );
- return -1;
- }
-
- if( i_tcp > 0 && FD_ISSET( p_access->socket_tcp.i_handle, &fds ) )
- {
- i_tcp_read =
- recv( p_access->socket_tcp.i_handle,
- p_access->buffer_tcp + p_access->i_buffer_tcp,
- i_tcp + MMS_BUFFER_SIZE/2, 0 );
- }
- else
- {
- i_tcp_read = 0;
- }
-
- if( i_udp > 0 && FD_ISSET( p_access->socket_udp.i_handle, &fds ) )
- {
- i_udp_read = recv( p_access->socket_udp.i_handle,
- p_access->buffer_udp + p_access->i_buffer_udp,
- i_udp + MMS_BUFFER_SIZE/2, 0 );
- }
- else
- {
- i_udp_read = 0;
- }
-
-#if 1
- if( p_access->i_proto == MMS_PROTO_UDP )
- {
- msg_Dbg( p_input,
- "filling buffer TCP:%d+%d UDP:%d+%d",
- p_access->i_buffer_tcp,
- i_tcp_read,
- p_access->i_buffer_udp,
- i_udp_read );
- }
- else
- {
- msg_Dbg( p_input,
- "filling buffer TCP:%d+%d",
- p_access->i_buffer_tcp,
- i_tcp_read );
- }
-#endif
- p_access->i_buffer_tcp += i_tcp_read;
- p_access->i_buffer_udp += i_udp_read;
-
- return( i_tcp_read + i_udp_read);
-#endif
-}
-
-static int mms_ParseCommand( input_thread_t *p_input,
- uint8_t *p_data,
- int i_data,
- int *pi_used )
-{
- #define GET32( i_pos ) \
- ( p_access->p_cmd[i_pos] + ( p_access->p_cmd[i_pos +1] << 8 ) + \
- ( p_access->p_cmd[i_pos + 2] << 16 ) + \
- ( p_access->p_cmd[i_pos + 3] << 24 ) )
-
- access_t *p_access = (access_t*)p_input->p_access_data;
- int i_length;
- uint32_t i_id;
-
- if( p_access->p_cmd )
- {
- free( p_access->p_cmd );
- }
- p_access->i_cmd = i_data;
- p_access->p_cmd = malloc( i_data );
- memcpy( p_access->p_cmd, p_data, i_data );
-
- *pi_used = i_data; /* by default */
-
- if( i_data < MMS_CMD_HEADERSIZE )
- {
- msg_Warn( p_input, "truncated command (header incomplete)" );
- p_access->i_command = 0;
- return( -1 );
- }
- i_id = GetDWLE( p_data + 4 );
- i_length = GetDWLE( p_data + 8 ) + 16;
-
- if( i_id != 0xb00bface )
- {
- msg_Err( p_input,
- "incorrect command header (0x%x)", i_id );
- p_access->i_command = 0;
- return( -1 );
- }
-
- if( i_length > p_access->i_cmd )
- {
- msg_Warn( p_input,
- "truncated command (missing %d bytes)",
- i_length - i_data );
- p_access->i_command = 0;
- return( -1 );
- }
- else if( i_length < p_access->i_cmd )
- {
- p_access->i_cmd = i_length;
- *pi_used = i_length;
- }
-
- msg_Dbg( p_input,
- "recv command start_sequence:0x%8.8x command_id:0x%8.8x length:%d len8:%d sequence 0x%8.8x len8_II:%d dir_comm:0x%8.8x",
- GET32( 0 ),
- GET32( 4 ),
- GET32( 8 ),
- /* 12: protocol type "MMS " */
- GET32( 16 ),
- GET32( 20 ),
- /* 24: unknown (0) */
- /* 28: unknown (0) */
- GET32( 32 ),
- GET32( 36 )
- /* 40: switches */
- /* 44: extra */ );
-
- p_access->i_command = GET32( 36 ) & 0xffff;
-
- return( MMS_PACKET_CMD );
-}
-
-static int mms_ParsePacket( input_thread_t *p_input,
- uint8_t *p_data, size_t i_data,
- int *pi_used )
-{
- access_t *p_access = (access_t*)p_input->p_access_data;
- int i_packet_seq_num;
- size_t i_packet_length;
- uint32_t i_packet_id;
-
- uint8_t *p_packet;
-
-
-// *pi_used = i_data; /* default */
- *pi_used = i_data; /* default */
- if( i_data <= 8 )
- {
- msg_Warn( p_input, "truncated packet (header incomplete)" );
- return( -1 );
- }
-
- i_packet_id = p_data[4];
- i_packet_seq_num = GetDWLE( p_data );
- i_packet_length = GetWLE( p_data + 6 );
-
-
- if( i_packet_length > i_data || i_packet_length <= 8)
- {
- msg_Warn( p_input,
- "truncated packet (missing %d bytes)",
- i_packet_length - i_data );
- *pi_used = 0;
- return( -1 );
- }
- else if( i_packet_length < i_data )
- {
- *pi_used = i_packet_length;
- }
-
- if( i_packet_id == 0xff )
- {
- msg_Warn( p_input,
- "receive MMS UDP pair timing" );
- return( MMS_PACKET_UDP_TIMING );
- }
-
- if( i_packet_id != p_access->i_header_packet_id_type &&
- i_packet_id != p_access->i_media_packet_id_type )
- {
- msg_Warn( p_input, "incorrect Packet Id Type (0x%x)", i_packet_id );
- return( -1 );
- }
-
- /* we now have a media or a header packet */
- p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
- memcpy( p_packet, p_data + 8, i_packet_length - 8 );
-
- if( i_packet_seq_num != p_access->i_packet_seq_num )
- {
- /* FIXME for udp could be just wrong order ? */
- msg_Warn( p_input,
- "detected packet lost (%d != %d)",
- i_packet_seq_num,
- p_access->i_packet_seq_num );
- p_access->i_packet_seq_num = i_packet_seq_num;
- }
- p_access->i_packet_seq_num++;
-
- if( i_packet_id == p_access->i_header_packet_id_type )
- {
- FREE( p_access->p_header );
- p_access->p_header = p_packet;
- p_access->i_header = i_packet_length - 8;
-/* msg_Dbg( p_input,
- "receive header packet (%d bytes)",
- i_packet_length - 8 ); */
-
- return( MMS_PACKET_HEADER );
- }
- else
- {
- FREE( p_access->p_media );
- p_access->p_media = p_packet;
- p_access->i_media = i_packet_length - 8;
- p_access->i_media_used = 0;
-/* msg_Dbg( p_input,
- "receive media packet (%d bytes)",
- i_packet_length - 8 ); */
-
- return( MMS_PACKET_MEDIA );
- }
-}
-
-static int mms_ReceivePacket( input_thread_t *p_input )
-{
- access_t *p_access = (access_t*)p_input->p_access_data;
- int i_packet_tcp_type;
- int i_packet_udp_type;
-
- for( ;; )
- {
- if( NetFillBuffer( p_input ) < 0 )
- {
- msg_Warn( p_input, "cannot fill buffer" );
- continue;
- }
- /* TODO udp */
-
- i_packet_tcp_type = -1;
- i_packet_udp_type = -1;
-
- if( p_access->i_buffer_tcp > 0 )
- {
- int i_used;
-
- if( GetDWLE( p_access->buffer_tcp + 4 ) == 0xb00bface )
- {
- i_packet_tcp_type =
- mms_ParseCommand( p_input,
- p_access->buffer_tcp,
- p_access->i_buffer_tcp,
- &i_used );
-
- }
- else
- {
- i_packet_tcp_type =
- mms_ParsePacket( p_input,
- p_access->buffer_tcp,
- p_access->i_buffer_tcp,
- &i_used );
- }
- if( i_used < MMS_BUFFER_SIZE )
- {
- memmove( p_access->buffer_tcp,
- p_access->buffer_tcp + i_used,
- MMS_BUFFER_SIZE - i_used );
- }
- p_access->i_buffer_tcp -= i_used;
- }
- else if( p_access->i_buffer_udp > 0 )
- {
- int i_used;
-#if 0
- if( GetDWLE( p_access->buffer_tcp + 4 ) == 0xb00bface )
- {
- i_packet_tcp_type =
- mms_ParseCommand( p_input,
- p_access->buffer_tcp,
- p_access->i_buffer_tcp,
- &i_used );
-
- }
- else
-#endif
- {
- i_packet_tcp_type =
- mms_ParsePacket( p_input,
- p_access->buffer_udp,
- p_access->i_buffer_udp,
- &i_used );
- }
- if( i_used < MMS_BUFFER_SIZE )
- {
- memmove( p_access->buffer_udp,
- p_access->buffer_udp + i_used,
- MMS_BUFFER_SIZE - i_used );
- }
- p_access->i_buffer_udp -= i_used;
- }
- else
- {
- i_packet_udp_type = -1;
- }
-
- if( i_packet_tcp_type == MMS_PACKET_CMD &&
- p_access->i_command == 0x1b )
- {
- mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
- i_packet_tcp_type = -1;
- }
-
- if( i_packet_tcp_type != -1 )
- {
- return( i_packet_tcp_type );
- }
- else if( i_packet_udp_type != -1 )
- {
- return( i_packet_udp_type );
- }
-
- }
-}
-
-static int mms_ReceiveCommand( input_thread_t *p_input )
-{
- access_t *p_access = (access_t*)p_input->p_access_data;
-
- for( ;; )
- {
- int i_used;
- int i_status;
- NetFillBuffer( p_input );
-
- i_status = mms_ParseCommand( p_input,
- p_access->buffer_tcp,
- p_access->i_buffer_tcp,
- &i_used );
- if( i_used < MMS_BUFFER_SIZE )
- {
- memmove( p_access->buffer_tcp,
- p_access->buffer_tcp + i_used,
- MMS_BUFFER_SIZE - i_used );
- }
- p_access->i_buffer_tcp -= i_used;
-
- if( i_status < 0 )
- {
- return( -1 );
- }
-
- if( p_access->i_command == 0x1b )
- {
- mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
- }
- else
- {
- break;
- }
- }
-
- return( 0 );
-}
-
-#define MMS_RETRY_MAX 10
-#define MMS_RETRY_SLEEP 50000
-
-static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 )
-{
- access_t *p_access = (access_t*)p_input->p_access_data;
- int i_count;
- int i_status;
-
- for( i_count = 0; i_count < MMS_RETRY_MAX; )
- {
-
- i_status = mms_ReceiveCommand( p_input );
- if( i_status < 0 || p_access->i_command == 0 )
- {
- i_count++;
- msleep( MMS_RETRY_SLEEP );
- }
- else if( i_command1 == 0 && i_command2 == 0)
- {
- return( 0 );
- }
- else if( p_access->i_command == i_command1 || p_access->i_command == i_command2 )
- {
- return( 0 );
- }
- else
- {
- switch( p_access->i_command )
- {
- case 0x03:
- msg_Warn( p_input, "socket closed by server" );
- p_access->i_eos = 1;
- return( -1 );
- case 0x1e:
- msg_Warn( p_input, "end of media stream" );
- p_access->i_eos = 1;
- return( -1 );
- default:
- break;
- }
- }
- }
- msg_Warn( p_input, "failed to receive command (abording)" );
-
- return( -1 );
-}
-
-
-static int mms_HeaderMediaRead( input_thread_t *p_input, int i_type )
-{
- access_t *p_access = (access_t*)p_input->p_access_data;
- int i_count;
-
- for( i_count = 0; i_count < MMS_RETRY_MAX; )
- {
- int i_status;
-
- i_status = mms_ReceivePacket( p_input );
- if( i_status < 0 )
- {
- i_count++;
- msg_Warn( p_input,
- "cannot receive header (%d/%d)", i_count, MMS_RETRY_MAX );
- msleep( MMS_RETRY_SLEEP );
- }
- else if( i_status == i_type || i_type == MMS_PACKET_ANY )
- {
- return( i_type );
- }
- else if( i_status == MMS_PACKET_CMD )
- {
- switch( p_access->i_command )
- {
- case 0x03:
- msg_Warn( p_input, "socket closed by server" );
- p_access->i_eos = 1;
- return( -1 );
- case 0x1e:
- msg_Warn( p_input, "end of media stream" );
- p_access->i_eos = 1;
- return( -1 );
- case 0x20:
- /* XXX not too dificult to be done EXCEPT that we
- * need to restart demuxer... and I don't see how we
- * could do that :p */
- msg_Err( p_input,
- "reinitialization needed --> unsupported" );
- p_access->i_eos = 1;
- return( -1 );
- default:
- break;
- }
- }
- }
- msg_Err( p_input,
- "cannot receive %s (abording)",
- ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );
- return( -1 );
-}
-