X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fmms%2Fmmstu.c;h=f0d600f774844b87dc3e72363d6beb6050f956e8;hb=5cc974b1a4bb383006a380d4c9e0011e47cefde1;hp=ccaec7006456fd5b3e2352a471e1f893778acc96;hpb=3b6a46b8c57fa04cf87d17777cb33f2bd83a448b;p=vlc diff --git a/modules/access/mms/mmstu.c b/modules/access/mms/mmstu.c index ccaec70064..f0d600f774 100644 --- a/modules/access/mms/mmstu.c +++ b/modules/access/mms/mmstu.c @@ -1,7 +1,7 @@ /***************************************************************************** * mms.c: MMS access plug-in ***************************************************************************** - * Copyright (C) 2001, 2002 VideoLAN + * Copyright (C) 2001, 2002 the VideoLAN team * $Id$ * * Authors: Laurent Aimar @@ -18,45 +18,44 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ -#include -#include -#include -#include -#include -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#include -#include +#include +#include + +#include +#include #ifdef HAVE_UNISTD_H # include #endif - -#ifdef WIN32 -# include -# include -# ifndef IN_MULTICAST -# define IN_MULTICAST(a) IN_CLASSD(a) -# endif -#else -# include -# include -# if HAVE_ARPA_INET_H -# include -# elif defined( SYS_BEOS ) -# include -# endif +#ifdef HAVE_FCNTL_H +# include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_POLL +# include #endif -#include "network.h" +#include +#include "vlc_url.h" #include "asf.h" #include "buffer.h" @@ -73,11 +72,11 @@ /***************************************************************************** * Local prototypes *****************************************************************************/ -int E_( MMSTUOpen ) ( access_t * ); -void E_( MMSTUClose ) ( access_t * ); +int MMSTUOpen ( access_t * ); +void MMSTUClose ( access_t * ); -static int Read( access_t *, uint8_t *, int ); +static block_t *Block( access_t * ); static int Seek( access_t *, int64_t ); static int Control( access_t *, int, va_list ); @@ -94,46 +93,27 @@ static int mms_HeaderMediaRead( access_t *, int ); static int mms_ReceivePacket( access_t * ); +static void* KeepAliveThread( void * ); -/* - * XXX DON'T FREE MY MEMORY !!! XXX - * non mais :P - */ -/* - * Ok, ok, j'le ferai plus... - */ -/* - * Merci :)) - */ -/* - * Vous pourriez signer vos commentaires (même si on voit bien qui peut - * écrire ce genre de trucs :p), et écrire en anglais, bordel de - * merde :p. - */ -/* - * Alors la ouai ç'est fou les gens qui écrivent des commentaires sans les - * signer. Ca mériterait un coup de pied dans le cul ça :) - */ - -int E_(MMSTUOpen)( access_t *p_access ) +int MMSTUOpen( access_t *p_access ) { access_sys_t *p_sys; int i_proto; int i_status; /* Set up p_access */ - p_access->pf_read = Read; - p_access->pf_block = NULL; + access_InitFields( p_access ); + p_access->pf_read = NULL; + p_access->pf_block = Block; p_access->pf_control = Control; p_access->pf_seek = Seek; - p_access->info.i_update = 0; - p_access->info.i_size = 0; - p_access->info.i_pos = 0; - p_access->info.b_eof = VLC_FALSE; - p_access->info.i_title = 0; - p_access->info.i_seekpoint = 0; - p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) ); - memset( p_sys, 0, sizeof( access_sys_t ) ); + + p_access->p_sys = p_sys = calloc( 1, sizeof( access_sys_t ) ); + if( !p_sys ) return VLC_ENOMEM; + + p_sys->i_timeout = var_CreateGetInteger( p_access, "mms-timeout" ); + + vlc_mutex_init( &p_sys->lock_netwrite ); /* *** Parse URL and get server addr/port and path *** */ vlc_UrlParse( &p_sys->url, p_access->psz_path, 0 ); @@ -141,6 +121,8 @@ int E_(MMSTUOpen)( access_t *p_access ) { msg_Err( p_access, "invalid server name" ); vlc_UrlClean( &p_sys->url ); + vlc_mutex_destroy( &p_sys->lock_netwrite ); + free( p_sys ); return VLC_EGENERIC; } if( p_sys->url.i_port <= 0 ) @@ -168,7 +150,8 @@ int E_(MMSTUOpen)( access_t *p_access ) { /* first try with TCP and then UDP*/ if( ( i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_TCP ) ) ) { - i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_UDP ); + if( !p_access->b_die ) + i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_UDP ); } } else @@ -180,6 +163,8 @@ int E_(MMSTUOpen)( access_t *p_access ) { msg_Err( p_access, "cannot connect to server" ); vlc_UrlClean( &p_sys->url ); + vlc_mutex_destroy( &p_sys->lock_netwrite ); + free( p_sys ); return VLC_EGENERIC; } @@ -196,11 +181,11 @@ int E_(MMSTUOpen)( access_t *p_access ) } if( p_sys->i_packet_count <= 0 || ( p_sys->i_flags_broadcast >> 24 ) == 0x02 ) { - p_sys->b_seekable = VLC_FALSE; + p_sys->b_seekable = false; } else { - p_sys->b_seekable = VLC_TRUE; + p_sys->b_seekable = true; p_access->info.i_size = (uint64_t)p_sys->i_header + (uint64_t)p_sys->i_packet_count * (uint64_t)p_sys->i_packet_length; @@ -210,25 +195,55 @@ int E_(MMSTUOpen)( access_t *p_access ) if( MMSStart( p_access, 0xffffffff ) < 0 ) { msg_Err( p_access, "cannot start stream" ); - MMSClose( p_access ); - vlc_UrlClean( &p_sys->url ); + MMSTUClose ( p_access ); return VLC_EGENERIC; } + + /* Keep the connection alive when paused */ + p_sys->p_keepalive = malloc( sizeof( mmstu_keepalive_t ) ); + if( !p_sys->p_keepalive ) + { + MMSTUClose ( p_access ); + return VLC_ENOMEM; + } + p_sys->p_keepalive->p_access = p_access; + vlc_mutex_init( &p_sys->p_keepalive->lock ); + vlc_cond_init( &p_sys->p_keepalive->wait ); + p_sys->p_keepalive->b_paused = false; + if( vlc_clone( &p_sys->p_keepalive->handle, KeepAliveThread, + p_sys->p_keepalive, VLC_THREAD_PRIORITY_LOW ) ) + { + vlc_cond_destroy( &p_sys->p_keepalive->wait ); + vlc_mutex_destroy( &p_sys->p_keepalive->lock ); + free( p_sys->p_keepalive ); + p_sys->p_keepalive = NULL; + } + return VLC_SUCCESS; } /***************************************************************************** * Close: free unused data structures *****************************************************************************/ -void E_(MMSTUClose)( access_t *p_access ) +void MMSTUClose( access_t *p_access ) { access_sys_t *p_sys = p_access->p_sys; + if( p_sys->p_keepalive ) + { + vlc_cancel( p_sys->p_keepalive->handle ); + vlc_join( p_sys->p_keepalive->handle, NULL ); + vlc_cond_destroy( &p_sys->p_keepalive->wait ); + vlc_mutex_destroy( &p_sys->p_keepalive->lock ); + free( p_sys->p_keepalive ); + } + /* close connection with server */ MMSClose( p_access ); /* free memory */ vlc_UrlClean( &p_sys->url ); + vlc_mutex_destroy( &p_sys->lock_netwrite ); free( p_sys ); } @@ -239,46 +254,82 @@ void E_(MMSTUClose)( access_t *p_access ) static int Control( access_t *p_access, int i_query, va_list args ) { access_sys_t *p_sys = p_access->p_sys; - vlc_bool_t *pb_bool; - int *pi_int; + bool *pb_bool; + bool b_bool; int64_t *pi_64; - vlc_value_t val; + int i_int; switch( i_query ) { /* */ case ACCESS_CAN_SEEK: - pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* ); + pb_bool = (bool*)va_arg( args, bool* ); *pb_bool = p_sys->b_seekable; break; + case ACCESS_CAN_FASTSEEK: + pb_bool = (bool*)va_arg( args, bool* ); + *pb_bool = false; + break; + case ACCESS_CAN_PAUSE: - case ACCESS_CAN_CONTROL_PACE: - pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* ); - *pb_bool = VLC_FALSE; + pb_bool = (bool*)va_arg( args, bool* ); + *pb_bool = true; break; - /* */ - case ACCESS_GET_MTU: - pi_int = (int*)va_arg( args, int * ); - *pi_int = 3 * p_sys->i_packet_length; + case ACCESS_CAN_CONTROL_PACE: + pb_bool = (bool*)va_arg( args, bool* ); + +#if 0 /* Disable for now until we have a clock synchro algo + * which works with something else than MPEG over UDP */ + *pb_bool = false; +#endif + *pb_bool = true; break; + /* */ case ACCESS_GET_PTS_DELAY: pi_64 = (int64_t*)va_arg( args, int64_t * ); - var_Get( p_access, "mms-caching", &val ); - *pi_64 = (int64_t)var_GetInteger( p_access, "mms-caching" ) * I64C(1000); + *pi_64 = (int64_t)var_GetInteger( p_access, "mms-caching" ) * INT64_C(1000); + break; + + case ACCESS_GET_PRIVATE_ID_STATE: + i_int = (int)va_arg( args, int ); + pb_bool = (bool *)va_arg( args, bool * ); + + if( i_int < 0 || i_int > 127 ) + return VLC_EGENERIC; + *pb_bool = p_sys->asfh.stream[i_int].i_selected ? true : false; break; /* */ case ACCESS_SET_PAUSE_STATE: + b_bool = (bool)va_arg( args, int ); + if( b_bool ) + MMSStop( p_access ); + else + Seek( p_access, p_access->info.i_pos ); + + if( p_sys->p_keepalive ) + { + vlc_mutex_lock( &p_sys->p_keepalive->lock ); + p_sys->p_keepalive->b_paused = b_bool; + if( b_bool ) + vlc_cond_signal( &p_sys->p_keepalive->wait ); + vlc_mutex_unlock( &p_sys->p_keepalive->lock ); + } + break; + case ACCESS_GET_TITLE_INFO: case ACCESS_SET_TITLE: case ACCESS_SET_SEEKPOINT: + case ACCESS_SET_PRIVATE_ID_STATE: + case ACCESS_GET_CONTENT_TYPE: return VLC_EGENERIC; + default: - msg_Err( p_access, "unimplemented query in control" ); + msg_Warn( p_access, "unimplemented query in control" ); return VLC_EGENERIC; } @@ -319,7 +370,10 @@ static int Seek( access_t * p_access, int64_t i_pos ) i_packet = ( i_pos - p_sys->i_header ) / p_sys->i_packet_length; i_offset = ( i_pos - p_sys->i_header ) % p_sys->i_packet_length; } - msg_Dbg( p_access, "seeking to "I64Fd " (packet:%d)", i_pos, i_packet ); + if( p_sys->b_seekable && i_packet >= p_sys->i_packet_count ) + return VLC_EGENERIC; + + msg_Dbg( p_access, "seeking to %"PRId64 " (packet:%d)", i_pos, i_packet ); MMSStop( p_access ); msg_Dbg( p_access, "stream stopped (seek)" ); @@ -341,9 +395,14 @@ static int Seek( access_t * p_access, int64_t i_pos ) var_buffer_free( &buffer ); - while( !p_access->b_die ) + while( vlc_object_alive (p_access) ) { - mms_HeaderMediaRead( p_access, MMS_PACKET_CMD ); + if( mms_HeaderMediaRead( p_access, MMS_PACKET_CMD ) < 0 ) + { + p_access->info.b_eof = true; + return VLC_EGENERIC; + } + if( p_sys->i_command == 0x1e ) { msg_Dbg( p_access, "received 0x1e (seek)" ); @@ -351,9 +410,13 @@ static int Seek( access_t * p_access, int64_t i_pos ) } } - while( !p_access->b_die ) + while( vlc_object_alive (p_access) ) { - mms_HeaderMediaRead( p_access, MMS_PACKET_CMD ); + if( mms_HeaderMediaRead( p_access, MMS_PACKET_CMD ) < 0 ) + { + p_access->info.b_eof = true; + return VLC_EGENERIC; + } if( p_sys->i_command == 0x05 ) { msg_Dbg( p_access, "received 0x05 (seek)" ); @@ -362,65 +425,69 @@ static int Seek( access_t * p_access, int64_t i_pos ) } /* get a packet */ - mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ); + if( mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ) < 0 ) + { + p_access->info.b_eof = true; + return VLC_EGENERIC; + } + msg_Dbg( p_access, "Streaming restarted" ); p_sys->i_media_used += i_offset; p_access->info.i_pos = i_pos; - p_access->info.b_eof = VLC_FALSE; + p_access->info.b_eof = false; return VLC_SUCCESS; } /***************************************************************************** - * Read: + * Block: *****************************************************************************/ -static int Read( access_t *p_access, uint8_t *p_buffer, int i_len ) +static block_t *Block( access_t *p_access ) { access_sys_t *p_sys = p_access->p_sys; - size_t i_data; - size_t i_copy; - i_data = 0; + if( p_access->info.b_eof ) + return NULL; - /* *** now send data if needed *** */ - while( i_data < i_len ) + if( p_access->info.i_pos < p_sys->i_header ) { - if( p_access->info.i_pos < p_sys->i_header ) - { - i_copy = __MIN( i_len, p_sys->i_header - p_access->info.i_pos ); - memcpy( &p_buffer[i_data], &p_sys->p_header[p_access->info.i_pos], i_copy ); - i_data += i_copy; - p_access->info.i_pos += i_copy; - } - else if( p_sys->i_media_used < p_sys->i_media ) - { - i_copy = __MIN( i_len - i_data , - p_sys->i_media - p_sys->i_media_used ); - memcpy( &p_buffer[i_data], &p_sys->p_media[p_sys->i_media_used], i_copy ); - i_data += i_copy; - p_sys->i_media_used += i_copy; - p_access->info.i_pos += i_copy; - } - else if( p_sys->p_media != NULL && - p_sys->i_media_used < p_sys->i_packet_length ) - { - i_copy = __MIN( i_len - i_data, - p_sys->i_packet_length - p_sys->i_media_used); - memset( &p_buffer[i_data], 0, i_copy ); + const size_t i_copy = p_sys->i_header - p_access->info.i_pos; - i_data += i_copy; - p_sys->i_media_used += i_copy; - p_access->info.i_pos += i_copy; - } - else if( p_access->info.b_eof || - mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ) < 0 ) - { - break; - } + block_t *p_block = block_New( p_access, i_copy ); + if( !p_block ) + return NULL; + + memcpy( p_block->p_buffer, &p_sys->p_header[p_access->info.i_pos], i_copy ); + p_access->info.i_pos += i_copy; + return p_block; + } + else if( p_sys->p_media && p_sys->i_media_used < __MAX( p_sys->i_media, p_sys->i_packet_length ) ) + { + size_t i_copy = 0; + size_t i_padding = 0; + + if( p_sys->i_media_used < p_sys->i_media ) + i_copy = p_sys->i_media - p_sys->i_media_used; + if( __MAX( p_sys->i_media, p_sys->i_media_used ) < p_sys->i_packet_length ) + i_padding = p_sys->i_packet_length - __MAX( p_sys->i_media, p_sys->i_media_used ); + + block_t *p_block = block_New( p_access, i_copy + i_padding ); + if( !p_block ) + return NULL; + + if( i_copy > 0 ) + memcpy( &p_block->p_buffer[0], &p_sys->p_media[p_sys->i_media_used], i_copy ); + if( i_padding > 0 ) + memset( &p_block->p_buffer[i_copy], 0, i_padding ); + + p_sys->i_media_used += i_copy + i_padding; + p_access->info.i_pos += i_copy + i_padding; + return p_block; } - return i_data; + mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ); + return NULL; } /**************************************************************************** @@ -441,11 +508,12 @@ static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) int i; int i_streams; int i_first; + char *mediapath; /* *** Open a TCP connection with server *** */ msg_Dbg( p_access, "waiting for connection..." ); - p_sys->i_handle_tcp = net_OpenTCP( p_access, p_url->psz_host, p_url->i_port ); + p_sys->i_handle_tcp = net_ConnectTCP( p_access, p_url->psz_host, p_url->i_port ); if( p_sys->i_handle_tcp < 0 ) { msg_Err( p_access, "failed to open a connection (tcp)" ); @@ -459,18 +527,15 @@ static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) /* *** Bind port if UDP protocol is selected *** */ if( b_udp ) { - struct sockaddr_in name; - socklen_t i_namelen = sizeof( struct sockaddr_in ); - - if( getsockname( p_sys->i_handle_tcp, - (struct sockaddr*)&name, &i_namelen ) < 0 ) + if( net_GetSockAddress( p_sys->i_handle_tcp, p_sys->sz_bind_addr, + NULL ) ) { net_Close( p_sys->i_handle_tcp ); return VLC_EGENERIC; } - p_sys->psz_bind_addr = inet_ntoa( name.sin_addr ); - p_sys->i_handle_udp = net_OpenUDP( p_access, p_sys->psz_bind_addr, 7000, "", 0 ); + p_sys->i_handle_udp = net_ListenUDP1( (vlc_object_t *)p_access, p_sys->sz_bind_addr, + 7000 ); if( p_sys->i_handle_udp < 0 ) { msg_Err( p_access, "failed to open a connection (udp)" ); @@ -479,15 +544,11 @@ static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) } msg_Dbg( p_access, "connection(udp) at \"%s:%d\" successful", - p_sys->psz_bind_addr, 7000 ); - } - else - { - p_sys->psz_bind_addr = NULL; + p_sys->sz_bind_addr, 7000 ); } /* *** Init context for mms prototcol *** */ - E_( GenerateGuid )( &p_sys->guid ); /* used to identify client by server */ + GenerateGuid ( &p_sys->guid ); /* used to identify client by server */ msg_Dbg( p_access, "generated guid: "GUID_FMT, GUID_PRINT( p_sys->guid ) ); @@ -508,7 +569,7 @@ static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) p_sys->i_buffer_udp = 0; p_sys->p_cmd = NULL; p_sys->i_cmd = 0; - p_access->info.b_eof = 0; + p_access->info.b_eof = false; /* *** send command 1 : connection request *** */ var_buffer_initwrite( &buffer, 0 ); @@ -548,7 +609,7 @@ static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) psz[i] = p[i]; \ } \ psz[size] = '\0'; \ - p += 2 * ( size ); \ + p += ( size ); \ } GETUTF16( p_sys->psz_server_version, i_server_version ); GETUTF16( p_sys->psz_tool_version, i_tool_version ); @@ -573,7 +634,7 @@ static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) { sprintf( tmp, "\\\\%s\\UDP\\%d", - p_sys->psz_bind_addr, + p_sys->sz_bind_addr, 7000 ); // FIXME } else @@ -608,7 +669,14 @@ static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) /* *** 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 ); + + /* media file path shouldn't start with / character */ + mediapath = p_url->psz_path; + if ( *mediapath == '/' ) + { + mediapath++; + } + var_buffer_addUTF16( &buffer, mediapath ); mms_CommandSend( p_access, 0x05, @@ -643,10 +711,10 @@ static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) switch( GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) ) { case 0x0001: - msg_Dbg( p_access, "Media file name/path accepted" ); + msg_Dbg( p_access, "media file name/path accepted" ); break; case 0x0002: - msg_Dbg( p_access, "Authentication accepted" ); + msg_Dbg( p_access, "authentication accepted" ); break; case -1: default: @@ -671,10 +739,12 @@ static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 60 ); msg_Dbg( p_access, - "answer 0x06 flags:0x%8.8x media_length:%ds packet_length:%d packet_count:%d max_bit_rate:%d header_size:%d", + "answer 0x06 flags:0x%8.8"PRIx32" media_length:%"PRIu32"s " + "packet_length:%u packet_count:%"PRId32" max_bit_rate:%d " + "header_size:%zu", p_sys->i_flags_broadcast, p_sys->i_media_length, - p_sys->i_packet_length, + (unsigned)p_sys->i_packet_length, p_sys->i_packet_count, p_sys->i_max_bit_rate, p_sys->i_header_size ); @@ -725,12 +795,12 @@ static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) if( p_sys->i_header >= p_sys->i_header_size ) { msg_Dbg( p_access, - "header complete(%d)", + "header complete(%zu)", p_sys->i_header ); break; } msg_Dbg( p_access, - "header incomplete (%d/%d), reading more", + "header incomplete (%zu/%zu), reading more", p_sys->i_header, p_sys->i_header_size ); } @@ -740,9 +810,9 @@ static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) * * TODO : stream bitrates properties(optional) * and bitrate mutual exclusion(optional) */ - E_( asf_HeaderParse )( &p_sys->asfh, + asf_HeaderParse ( &p_sys->asfh, p_sys->p_header, p_sys->i_header ); - E_( asf_StreamSelect)( &p_sys->asfh, + asf_StreamSelect( &p_sys->asfh, var_CreateGetInteger( p_access, "mms-maxbitrate" ), var_CreateGetInteger( p_access, "mms-all" ), var_CreateGetInteger( p_access, "audio" ), @@ -819,7 +889,7 @@ static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) var_buffer_free( &buffer ); - msg_Info( p_access, "connection sucessful" ); + msg_Info( p_access, "connection successful" ); return VLC_SUCCESS; } @@ -855,14 +925,15 @@ static int MMSStart( access_t *p_access, uint32_t i_packet ) msg_Err( p_access, "unknown answer (0x%x instead of 0x05)", p_sys->i_command ); - return( -1 ); + return -1; } else { /* get a packet */ - mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ); - msg_Dbg( p_access, "Streaming started" ); - return( 0 ); + if( mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ) < 0 ) + return -1; + msg_Dbg( p_access, "streaming started" ); + return 0; } } @@ -905,14 +976,14 @@ static void MMSClose( access_t *p_access ) net_Close( p_sys->i_handle_udp ); } - FREE( p_sys->p_cmd ); - FREE( p_sys->p_media ); - FREE( p_sys->p_header ); + FREENULL( p_sys->p_cmd ); + FREENULL( p_sys->p_media ); + FREENULL( p_sys->p_header ); - FREE( p_sys->psz_server_version ); - FREE( p_sys->psz_tool_version ); - FREE( p_sys->psz_update_player_url ); - FREE( p_sys->psz_encryption_type ); + FREENULL( p_sys->psz_server_version ); + FREENULL( p_sys->psz_tool_version ); + FREENULL( p_sys->psz_update_player_url ); + FREENULL( p_sys->psz_encryption_type ); } /**************************************************************************** @@ -920,19 +991,19 @@ static void MMSClose( access_t *p_access ) * MMS specific functions * ****************************************************************************/ -static int mms_CommandSend( access_t *p_access, - int i_command, - uint32_t i_prefix1, uint32_t i_prefix2, - uint8_t *p_data, int i_data ) +static int mms_CommandSend( access_t *p_access, int i_command, + uint32_t i_prefix1, uint32_t i_prefix2, + uint8_t *p_data, int i_data_old ) { var_buffer_t buffer; + access_sys_t *p_sys = p_access->p_sys; + int i_data_by8, i_ret; + int i_data = i_data_old; - access_sys_t *p_sys = p_access->p_sys; - int i_data_by8; - - i_data_by8 = ( i_data + 7 ) / 8; + while( i_data & 0x7 ) i_data++; + i_data_by8 = i_data >> 3; - /* first init uffer */ + /* first init buffer */ var_buffer_initwrite( &buffer, 0 ); var_buffer_add32( &buffer, 0x00000001 ); /* start sequence */ @@ -951,14 +1022,18 @@ static int mms_CommandSend( access_t *p_access, /* specific command data */ if( p_data && i_data > 0 ) { - var_buffer_addmemory( &buffer, p_data, i_data ); + var_buffer_addmemory( &buffer, p_data, i_data_old ); } + /* Append padding to the command data */ + var_buffer_add64( &buffer, 0 ); + /* send it */ - if( send( p_sys->i_handle_tcp, - buffer.p_data, - buffer.i_data, - 0 ) == -1 ) + vlc_mutex_lock( &p_sys->lock_netwrite ); + i_ret = net_Write( p_access, p_sys->i_handle_tcp, NULL, buffer.p_data, + buffer.i_data - ( 8 - ( i_data - i_data_old ) ) ); + vlc_mutex_unlock( &p_sys->lock_netwrite ); + if( i_ret != buffer.i_data - ( 8 - ( i_data - i_data_old ) ) ) { msg_Err( p_access, "failed to send command" ); return VLC_EGENERIC; @@ -975,14 +1050,13 @@ static int NetFillBuffer( access_t *p_access ) #else access_sys_t *p_sys = p_access->p_sys; - struct timeval timeout; - fd_set fds_r, fds_e; int i_ret; + struct pollfd ufd[2]; + unsigned timeout, nfd; /* FIXME when using udp */ ssize_t i_tcp, i_udp; ssize_t i_tcp_read, i_udp_read; - int i_handle_max; int i_try = 0; i_tcp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_tcp; @@ -996,16 +1070,9 @@ static int NetFillBuffer( access_t *p_access ) i_udp = 0; /* there isn't udp socket */ } - i_handle_max = 0; - - if( i_tcp > 0 ) - i_handle_max = __MAX( i_handle_max, p_sys->i_handle_tcp ); - if( i_udp > 0 ) - i_handle_max = __MAX( i_handle_max, p_sys->i_handle_udp ); - - if( i_handle_max == 0 ) + if( ( i_udp <= 0 ) && ( i_tcp <= 0 ) ) { - msg_Warn( p_access, "nothing to read %d:%d", i_tcp, i_udp ); + msg_Warn( p_access, "nothing to read %d:%d", (int)i_tcp, (int)i_udp ); return 0; } else @@ -1019,45 +1086,53 @@ static int NetFillBuffer( access_t *p_access ) i_try++; /* Initialize file descriptor set */ - FD_ZERO( &fds_r ); - FD_ZERO( &fds_e ); + memset (ufd, 0, sizeof (ufd)); + nfd = 0; if( i_tcp > 0 ) { - FD_SET( p_sys->i_handle_tcp, &fds_r ); - FD_SET( p_sys->i_handle_tcp, &fds_e ); + ufd[nfd].fd = p_sys->i_handle_tcp; + ufd[nfd].events = POLLIN; + nfd++; } if( i_udp > 0 ) { - FD_SET( p_sys->i_handle_udp, &fds_r ); - FD_SET( p_sys->i_handle_udp, &fds_e ); + ufd[nfd].fd = p_sys->i_handle_udp; + ufd[nfd].events = POLLIN; + nfd++; } /* We'll wait 0.5 second if nothing happens */ - timeout.tv_sec = 0; - timeout.tv_usec = 500000; + timeout = __MIN( 500, p_sys->i_timeout ); + + if( i_try * timeout > p_sys->i_timeout ) + { + msg_Err(p_access, "no data received"); + return -1; + } if( i_try > 3 && (p_sys->i_buffer_tcp > 0 || p_sys->i_buffer_udp > 0) ) { return -1; } - if( p_access->b_die || p_access->b_error ) return -1; + if( !vlc_object_alive (p_access) || p_access->b_error ) + return -1; //msg_Dbg( p_access, "NetFillBuffer: trying again (select)" ); - } while( !(i_ret = select(i_handle_max +1, &fds_r, 0, &fds_e, &timeout)) || + } while( !(i_ret = poll( ufd, nfd, timeout)) || (i_ret < 0 && errno == EINTR) ); if( i_ret < 0 ) { - msg_Err( p_access, "network select error (%s)", strerror(errno) ); + msg_Err( p_access, "network poll error (%m)" ); return -1; } i_tcp_read = i_udp_read = 0; - if( i_tcp > 0 && FD_ISSET( p_sys->i_handle_tcp, &fds_r ) ) + if( ( i_tcp > 0 ) && ufd[0].revents ) { i_tcp_read = recv( p_sys->i_handle_tcp, @@ -1065,14 +1140,14 @@ static int NetFillBuffer( access_t *p_access ) i_tcp + MMS_BUFFER_SIZE/2, 0 ); } - if( i_udp > 0 && FD_ISSET( p_sys->i_handle_udp, &fds_r ) ) + if( i_udp > 0 && ufd[i_tcp > 0].revents ) { i_udp_read = recv( p_sys->i_handle_udp, p_sys->buffer_udp + p_sys->i_buffer_udp, i_udp + MMS_BUFFER_SIZE/2, 0 ); } -#if MMS_DEBUG +#ifdef MMS_DEBUG if( p_sys->i_proto == MMS_PROTO_UDP ) { msg_Dbg( p_access, "filling buffer TCP:%d+%d UDP:%d+%d", @@ -1095,7 +1170,7 @@ static int NetFillBuffer( access_t *p_access ) static int mms_ParseCommand( access_t *p_access, uint8_t *p_data, - int i_data, + size_t i_data, int *pi_used ) { #define GET32( i_pos ) \ @@ -1104,13 +1179,10 @@ static int mms_ParseCommand( access_t *p_access, ( p_sys->p_cmd[i_pos + 3] << 24 ) ) access_sys_t *p_sys = p_access->p_sys; - int i_length; + uint32_t i_length; uint32_t i_id; - if( p_sys->p_cmd ) - { - free( p_sys->p_cmd ); - } + free( p_sys->p_cmd ); p_sys->i_cmd = i_data; p_sys->p_cmd = malloc( i_data ); memcpy( p_sys->p_cmd, p_data, i_data ); @@ -1126,10 +1198,10 @@ static int mms_ParseCommand( access_t *p_access, i_id = GetDWLE( p_data + 4 ); i_length = GetDWLE( p_data + 8 ) + 16; - if( i_id != 0xb00bface ) + if( i_id != 0xb00bface || i_length < 16 ) { msg_Err( p_access, - "incorrect command header (0x%x)", i_id ); + "incorrect command header (0x%"PRIx32")", i_id ); p_sys->i_command = 0; return -1; } @@ -1137,8 +1209,8 @@ static int mms_ParseCommand( access_t *p_access, if( i_length > p_sys->i_cmd ) { msg_Warn( p_access, - "truncated command (missing %d bytes)", - i_length - i_data ); + "truncated command (missing %zu bytes)", + (size_t)i_length - i_data ); p_sys->i_command = 0; return -1; } @@ -1178,9 +1250,6 @@ static int mms_ParsePacket( access_t *p_access, size_t i_packet_length; uint32_t i_packet_id; - uint8_t *p_packet; - - *pi_used = i_data; /* default */ if( i_data <= 8 ) { @@ -1196,9 +1265,9 @@ static int mms_ParsePacket( access_t *p_access, if( i_packet_length > i_data || i_packet_length <= 8) { - msg_Dbg( p_access, - "truncated packet (missing %d bytes)", - i_packet_length - i_data ); + /* msg_Dbg( p_access, + "truncated packet (Declared %d bytes, Actual %d bytes)", + i_packet_length, i_data ); */ *pi_used = 0; return -1; } @@ -1222,19 +1291,17 @@ static int mms_ParsePacket( access_t *p_access, } /* 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_sys->i_packet_seq_num ) { +#if 0 /* FIXME for udp could be just wrong order ? */ msg_Warn( p_access, "detected packet lost (%d != %d)", i_packet_seq_num, p_sys->i_packet_seq_num ); - p_sys->i_packet_seq_num = i_packet_seq_num; +#endif } - p_sys->i_packet_seq_num++; + p_sys->i_packet_seq_num = i_packet_seq_num + 1; if( i_packet_id == p_sys->i_header_packet_id_type ) { @@ -1243,14 +1310,14 @@ static int mms_ParsePacket( access_t *p_access, p_sys->p_header = realloc( p_sys->p_header, p_sys->i_header + i_packet_length - 8 ); memcpy( &p_sys->p_header[p_sys->i_header], - p_packet, - i_packet_length - 8 ); + p_data + 8, i_packet_length - 8 ); p_sys->i_header += i_packet_length - 8; - free( p_packet ); } else { + uint8_t* p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader + memcpy( p_packet, p_data + 8, i_packet_length - 8 ); p_sys->p_header = p_packet; p_sys->i_header = i_packet_length - 8; } @@ -1262,7 +1329,9 @@ static int mms_ParsePacket( access_t *p_access, } else { - FREE( p_sys->p_media ); + uint8_t* p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader + memcpy( p_packet, p_data + 8, i_packet_length - 8 ); + FREENULL( p_sys->p_media ); p_sys->p_media = p_packet; p_sys->i_media = i_packet_length - 8; p_sys->i_media_used = 0; @@ -1282,7 +1351,7 @@ static int mms_ReceivePacket( access_t *p_access ) for( ;; ) { - vlc_bool_t b_refill = VLC_TRUE; + bool b_refill = true; /* first if we need to refill buffer */ if( p_sys->i_buffer_tcp >= MMS_CMD_HEADERSIZE ) @@ -1290,20 +1359,20 @@ static int mms_ReceivePacket( access_t *p_access ) if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface ) { if( GetDWLE( p_sys->buffer_tcp + 8 ) + 16 <= - p_sys->i_buffer_tcp ) + (uint32_t)p_sys->i_buffer_tcp ) { - b_refill = VLC_FALSE; + b_refill = false; } } else if( GetWLE( p_sys->buffer_tcp + 6 ) <= p_sys->i_buffer_tcp ) { - b_refill = VLC_FALSE; + b_refill = false; } } if( p_sys->i_proto == MMS_PROTO_UDP && p_sys->i_buffer_udp >= 8 && GetWLE( p_sys->buffer_udp + 6 ) <= p_sys->i_buffer_udp ) { - b_refill = VLC_FALSE; + b_refill = false; } if( b_refill && NetFillBuffer( p_access ) < 0 ) @@ -1453,17 +1522,18 @@ static int mms_CommandRead( access_t *p_access, int i_command1, { case 0x03: msg_Warn( p_access, "socket closed by server" ); - p_access->info.b_eof = 1; + p_access->info.b_eof = true; return VLC_EGENERIC; case 0x1e: msg_Warn( p_access, "end of media stream" ); - p_access->info.b_eof = 1; + p_access->info.b_eof = true; return VLC_EGENERIC; default: break; } } } + p_access->info.b_eof = true; msg_Warn( p_access, "failed to receive command (aborting)" ); return VLC_EGENERIC; @@ -1479,7 +1549,7 @@ static int mms_HeaderMediaRead( access_t *p_access, int i_type ) { int i_status; - if( p_access->b_die ) + if( !vlc_object_alive (p_access) ) return -1; i_status = mms_ReceivePacket( p_access ); @@ -1500,11 +1570,11 @@ static int mms_HeaderMediaRead( access_t *p_access, int i_type ) { case 0x03: msg_Warn( p_access, "socket closed by server" ); - p_access->info.b_eof = 1; + p_access->info.b_eof = true; return -1; case 0x1e: msg_Warn( p_access, "end of media stream" ); - p_access->info.b_eof = 1; + p_access->info.b_eof = true; return -1; case 0x20: /* XXX not too dificult to be done EXCEPT that we @@ -1512,7 +1582,7 @@ static int mms_HeaderMediaRead( access_t *p_access, int i_type ) * could do that :p */ msg_Err( p_access, "reinitialization needed --> unsupported" ); - p_access->info.b_eof = VLC_TRUE; + p_access->info.b_eof = true; return -1; default: break; @@ -1522,6 +1592,42 @@ static int mms_HeaderMediaRead( access_t *p_access, int i_type ) msg_Err( p_access, "cannot receive %s (aborting)", ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" ); + p_access->info.b_eof = true; return -1; } +static void* KeepAliveThread( void *p_data ) +{ + mmstu_keepalive_t *p_thread = (mmstu_keepalive_t *) p_data; + access_t *p_access = p_thread->p_access; + + vlc_mutex_lock( &p_thread->lock ); + mutex_cleanup_push( &p_thread->lock ); + + for( ;; ) + { + /* Do nothing until paused (if ever) */ + while( !p_thread->b_paused ) + vlc_cond_wait( &p_thread->wait, &p_thread->lock ); + + do + { + int canc; + + /* Send keep-alive every ten seconds */ + vlc_mutex_unlock( &p_thread->lock ); + canc = vlc_savecancel(); + + mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 ); + + vlc_restorecancel( canc ); + vlc_mutex_lock( &p_thread->lock ); + + msleep( 10 * CLOCK_FREQ ); + } + while( p_thread->b_paused ); + } + + vlc_cleanup_pop(); + assert(0); +}