* http.c
*****************************************************************************
* Copyright (C) 2001-2003 VideoLAN
- * $Id: http.c,v 1.1 2003/02/23 19:05:22 fenrir Exp $
+ * $Id: http.c,v 1.2 2003/02/25 17:17:43 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
/* stream */
httpd_stream_t *p_httpd_stream;
+
+ /* gather header from stream */
+ int i_header_allocated;
+ int i_header_size;
+ uint8_t *p_header;
+ vlc_bool_t b_header_complete;
+};
+
+static struct
+{
+ char *psz_ext;
+ char *psz_mime;
+} http_mime[] =
+{
+ { ".avi", "video/avi" },
+ { ".asf", "video/x-ms-asf" },
+ { ".m1a", "audio/mpeg" },
+ { ".m2a", "audio/mpeg" },
+ { ".m1v", "video/mpeg" },
+ { ".m2v", "video/mpeg" },
+ { ".mp2", "audio/mpeg" },
+ { ".mp3", "audio/mpeg" },
+ { ".mpa", "audio/mpeg" },
+ { ".mpg", "video/mpeg" },
+ { ".mpeg", "video/mpeg" },
+ { ".mpe", "video/mpeg" },
+ { ".mov", "video/quicktime" },
+ { ".moov", "video/quicktime" },
+ { ".ogg", "application/ogg" },
+ { ".ogm", "application/ogg" },
+ { ".wav", "audio/wav" },
+ { NULL, NULL }
};
+static char *GetMime( char *psz_name )
+{
+ char *psz_ext;
+
+ psz_ext = strrchr( psz_name, '.' );
+ if( psz_ext )
+ {
+ int i;
+
+ for( i = 0; http_mime[i].psz_ext != NULL ; i++ )
+ {
+ if( !strcmp( http_mime[i].psz_ext, psz_ext ) )
+ {
+ return( http_mime[i].psz_mime );
+ }
+ }
+ }
+ return( "application/octet-stream" );
+}
/*****************************************************************************
* Open: open the file
*****************************************************************************/
p_sys->p_httpd_stream =
p_sys->p_httpd->pf_register_stream( p_sys->p_httpd,
- psz_file_name, "application/x-octet_stream",
+ psz_file_name,
+ GetMime( psz_file_name ),
NULL, NULL );
if( !p_sys->p_httpd_stream )
return( VLC_EGENERIC );
}
+ p_sys->i_header_allocated = 1024;
+ p_sys->i_header_size = 0;
+ p_sys->p_header = malloc( p_sys->i_header_allocated );
+ p_sys->b_header_complete = VLC_FALSE;
+
p_access->pf_write = Write;
p_access->pf_seek = Seek;
httpd_Release( p_sys->p_httpd );
+ FREE( p_sys->p_header );
+
msg_Info( p_access, "Close" );
free( p_sys );
{
sout_buffer_t *p_next;
+ if( p_buffer->i_flags & SOUT_BUFFER_FLAGS_HEADER )
+ {
+ /* gather header */
+ if( p_sys->b_header_complete )
+ {
+ /* free previously gathered header */
+ p_sys->i_header_size = 0;
+ p_sys->b_header_complete = VLC_FALSE;
+ }
+ if( p_buffer->i_size + p_sys->i_header_size > p_sys->i_header_allocated )
+ {
+ p_sys->i_header_allocated = p_buffer->i_size + p_sys->i_header_size + 1024;
+ p_sys->p_header = realloc( p_sys->p_header, p_sys->i_header_allocated );
+ }
+ memcpy( &p_sys->p_header[p_sys->i_header_size],
+ p_buffer->p_buffer,
+ p_buffer->i_size );
+ p_sys->i_header_size += p_buffer->i_size;
+ }
+ else if( !p_sys->b_header_complete )
+ {
+ p_sys->b_header_complete = VLC_TRUE;
+
+ p_sys->p_httpd->pf_header_stream( p_sys->p_httpd,
+ p_sys->p_httpd_stream,
+ p_sys->p_header, p_sys->i_header_size );
+ }
+ /* send data */
i_err = p_sys->p_httpd->pf_send_stream( p_sys->p_httpd, p_sys->p_httpd_stream,
p_buffer->p_buffer, p_buffer->i_size );
break;
}
}
+
if( i_err < 0 )
{
sout_buffer_t *p_next;
* httpd.c
*****************************************************************************
* Copyright (C) 2001-2003 VideoLAN
- * $Id: httpd.c,v 1.2 2003/02/24 11:14:16 gbazin Exp $
+ * $Id: httpd.c,v 1.3 2003/02/25 17:17:43 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
/*****************************************************************************
* Prototypes
*****************************************************************************/
-static httpd_host_t *RegisterHost( httpd_t *, char *, int );
-static void UnregisterHost( httpd_t *, httpd_host_t * );
+static httpd_host_t *RegisterHost ( httpd_t *, char *, int );
+static void UnregisterHost ( httpd_t *, httpd_host_t * );
-static httpd_file_t *RegisterFile( httpd_t *,
- char *psz_file, char *psz_mime,
- char *psz_user, char *psz_password,
- httpd_file_callback pf_fill,
- httpd_file_callback_args_t *p_args );
-static void UnregisterFile( httpd_t *, httpd_file_t * );
+static httpd_file_t *RegisterFile ( httpd_t *,
+ char *psz_file, char *psz_mime,
+ char *psz_user, char *psz_password,
+ httpd_file_callback pf_fill,
+ httpd_file_callback_args_t *p_args );
+static void UnregisterFile ( httpd_t *, httpd_file_t * );
//#define httpd_stream_t httpd_file_t
-static httpd_stream_t *RegisterStream( httpd_t *,
+static httpd_stream_t *RegisterStream ( httpd_t *,
char *psz_file, char *psz_mime,
char *psz_user, char *psz_password );
-static int SendStream( httpd_t *, httpd_stream_t *, uint8_t *, int );
+static int SendStream ( httpd_t *, httpd_stream_t *, uint8_t *, int );
+static int HeaderStream ( httpd_t *, httpd_stream_t *, uint8_t *, int );
static void UnregisterStream( httpd_t *, httpd_stream_t* );
/*****************************************************************************
httpd_file_callback pf_fill; /* it should allocate and fill *pp_data and *pi_data */
/* private */
- int i_buffer_size; /* buffer size */
- uint8_t *p_buffer; /* buffer */
- int i_buffer; /* reading pointer */
- int i_buffer_valid; /* valid data from 0 */
+ /* circular buffer for stream only */
+ int i_buffer_size; /* buffer size, can't be reallocated smaller */
+ uint8_t *p_buffer; /* buffer */
+ int64_t i_buffer_pos; /* absolute position from begining */
+ int i_buffer_last_pos; /* a new connection will start with that */
+
+ /* data to be send at connection time (if any) */
+ int i_header_size;
+ uint8_t *p_header;
};
httpd_file_t *p_file;
+ /* used while sending header and file */
int i_buffer_size;
uint8_t *p_buffer;
- int i_buffer; /* private */
+ int i_buffer; /* private */
+
+ /* used for stream */
+ int64_t i_stream_pos; /* absolute pos in stream */
} httpd_connection_t;
/*
p_httpd->pf_register_file = RegisterFile;
p_httpd->pf_unregister_file = UnregisterFile;
p_httpd->pf_register_stream = RegisterStream;
+ p_httpd->pf_header_stream = HeaderStream;
p_httpd->pf_send_stream = SendStream;
p_httpd->pf_unregister_stream=UnregisterStream;
p_file->psz_password = NULL;
}
- p_file->b_stream = VLC_FALSE;
- p_file->p_sys = p_args;
- p_file->pf_fill = pf_fill;
+ p_file->b_stream = VLC_FALSE;
+ p_file->p_sys = p_args;
+ p_file->pf_fill = pf_fill;
+
+ p_file->i_buffer_size = 0;
+ p_file->i_buffer_last_pos = 0;
+ p_file->i_buffer_pos = 0;
+ p_file->p_buffer = NULL;
- p_file->i_buffer_size = 0;
- p_file->i_buffer_valid = 0;
- p_file->i_buffer = 0;
- p_file->p_buffer = NULL;
+ p_file->i_header_size = 0;
+ p_file->p_header = NULL;
__RegisterFile( p_httpt, p_file );
if( i < p_httpt->i_file_count )
{
vlc_mutex_unlock( &p_httpt->file_lock );
- msg_Err( p_httpt, "%s already registeret", psz_file );
+ msg_Err( p_httpt, "%s already registered", psz_file );
return NULL;
}
p_stream->b_stream = VLC_TRUE;
p_stream->p_sys = NULL;
p_stream->pf_fill = NULL;
- p_stream->i_buffer_size = 1024*1024;
- p_stream->i_buffer_valid = 0;
- p_stream->i_buffer = 0;
+
+ p_stream->i_buffer_size = 1024*1024*10;
+ p_stream->i_buffer_pos = 0;
+ p_stream->i_buffer_last_pos = 0;
p_stream->p_buffer = malloc( p_stream->i_buffer_size );
+ p_stream->i_header_size = 0;
+ p_stream->p_header = NULL;
+
__RegisterFile( p_httpt, p_stream );
vlc_mutex_unlock( &p_httpt->file_lock );
FREE( p_file->psz_password );
}
FREE( p_file->p_buffer );
+ FREE( p_file->p_header );
FREE( p_file );
static int _SendStream( httpd_sys_t *p_httpt, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
{
- if( i_data <= 0 )
+ int i_count;
+ int i_pos;
+
+ if( i_data <= 0 || p_data == NULL )
{
return( VLC_SUCCESS );
}
+ //fprintf( stderr, "## i_data=%d pos=%lld\n", i_data, p_stream->i_buffer_pos );
vlc_mutex_lock( &p_httpt->file_lock );
- if( p_stream->i_buffer_size < p_stream->i_buffer_valid + i_data )
+
+ /* save this pointer (to be used by new connection) */
+ p_stream->i_buffer_last_pos = p_stream->i_buffer_pos;
+
+ i_pos = p_stream->i_buffer_pos % p_stream->i_buffer_size;
+ i_count = i_data;
+ while( i_count > 0)
{
- /* not enough room */
- if( p_stream->i_buffer < p_stream->i_buffer_valid )
- {
- memmove( p_stream->p_buffer,
- p_stream->p_buffer + p_stream->i_buffer,
- p_stream->i_buffer_valid - p_stream->i_buffer );
- }
- p_stream->i_buffer_valid -= p_stream->i_buffer;
+ int i_copy;
- p_stream->i_buffer = 0;
+ i_copy = __MIN( i_data, p_stream->i_buffer_size - i_pos );
+
+ memcpy( &p_stream->p_buffer[i_pos],
+ p_data,
+ i_copy );
+
+ i_pos = ( i_pos + i_copy ) % p_stream->i_buffer_size;
+ i_count -= i_copy;
+ p_data += i_copy;
}
- i_data = __MIN( i_data, p_stream->i_buffer_size - p_stream->i_buffer_valid );
- memcpy( p_stream->p_buffer + p_stream->i_buffer_valid, p_data, i_data );
- p_stream->i_buffer_valid += i_data;
+ p_stream->i_buffer_pos += i_data;
vlc_mutex_unlock( &p_httpt->file_lock );
return( VLC_SUCCESS );
return( _SendStream( p_httpd->p_sys, p_stream, p_data, i_data ) );
}
+static int HeaderStream( httpd_t *p_httpd, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
+{
+ httpd_sys_t *p_httpt = p_httpd->p_sys;
+
+ vlc_mutex_lock( &p_httpt->file_lock );
+
+ FREE( p_stream->p_header );
+ if( p_data == NULL || i_data <= 0 )
+ {
+ p_stream->i_header_size = 0;
+ }
+ else
+ {
+ p_stream->i_header_size = i_data;
+ p_stream->p_header = malloc( i_data );
+ memcpy( p_stream->p_header,
+ p_data,
+ i_data );
+ }
+ vlc_mutex_unlock( &p_httpt->file_lock );
+
+ return( VLC_SUCCESS );
+}
+
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
p_con->i_buffer_size = 8096;
p_con->p_buffer = malloc( p_con->i_buffer_size );
+ p_con->i_stream_pos = 0; // updated by httpd_thread */
p_con->p_next = NULL;
if( p_httpt->p_first_connection )
p_con->i_state = HTTPD_CONNECTION_SENDING_HEADER;
+ /* we send stream header with this one */
+ if( p_con->i_http_error == 200 && p_con->p_file->b_stream )
+ {
+ p_con->i_buffer_size = 4096 + p_con->p_file->i_header_size;
+ }
+
p_con->i_buffer_size = 4096;
p_con->i_buffer = 0;
p = p_con->p_buffer = malloc( p_con->i_buffer_size );
}
p += sprintf( p, "\r\n" );
- p_con->i_buffer_size = strlen( p_con->p_buffer ) + 1;
+ p_con->i_buffer_size = strlen( p_con->p_buffer );// + 1;
+
+ if( p_con->i_http_error == 200 && p_con->p_file->b_stream && p_con->p_file->i_header_size > 0 )
+ {
+ /* add stream header */
+ memcpy( &p_con->p_buffer[p_con->i_buffer_size],
+ p_con->p_file->p_header,
+ p_con->p_file->i_header_size );
+ p_con->i_buffer_size += p_con->p_file->i_header_size;
+ }
//msg_Dbg( p_httpt, "answer=\n%s", p_con->p_buffer );
}
-#define HTTPD_STREAM_PACKET 1300
+#define HTTPD_STREAM_PACKET 10000
static void httpd_Thread( httpd_sys_t *p_httpt )
{
httpd_file_t *p_page_admin;
else
{
p_con->i_state = HTTPD_CONNECTION_SENDING_STREAM;
+ p_con->i_stream_pos = p_con->p_file->i_buffer_last_pos;
}
p_con = p_con->p_next;
}
}
else if( p_con->i_state == HTTPD_CONNECTION_SENDING_STREAM )
{
- httpd_file_t *p_file = p_con->p_file;
- int i_len;
+ httpd_stream_t *p_stream = p_con->p_file;
+ int i_send;
+ int i_write;
- //msg_Dbg( p_httpt, "buffer=%d buffer_size=%d", p_file->i_buffer, p_file->i_buffer_size );
- if( p_file->i_buffer < p_file->i_buffer_valid )
+ if( p_con->i_stream_pos < p_stream->i_buffer_pos )
{
- int i_write;
- /* write data */
- i_write = __MIN( p_file->i_buffer_valid - p_file->i_buffer, HTTPD_STREAM_PACKET );
- i_len = send( p_con->fd, p_file->p_buffer + p_file->i_buffer, i_write, 0 );
+ int i_pos;
+ /* check if this p_con aren't to late */
+ if( p_con->i_stream_pos + p_stream->i_buffer_size < p_stream->i_buffer_pos )
+ {
+ fprintf(stderr, "fixing i_stream_pos (old=%lld i_buffer_pos=%lld\n", p_con->i_stream_pos, p_stream->i_buffer_pos );
+ p_con->i_stream_pos = p_stream->i_buffer_last_pos;
+ }
- if( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
- ( i_len == 0 ) )
+ i_pos = p_con->i_stream_pos % p_stream->i_buffer_size;
+ /* size until end of buffer */
+ i_write = p_stream->i_buffer_size - i_pos;
+ /* is it more than valid data */
+ if( i_write >= p_stream->i_buffer_pos - p_con->i_stream_pos )
+ {
+ i_write = p_stream->i_buffer_pos - p_con->i_stream_pos;
+ }
+ /* limit to HTTPD_STREAM_PACKET */
+ if( i_write > HTTPD_STREAM_PACKET )
+ {
+ i_write = HTTPD_STREAM_PACKET;
+ }
+ i_send = send( p_con->fd, &p_stream->p_buffer[i_pos], i_write, 0 );
+
+ if( ( i_send < 0 && errno != EAGAIN && errno != EINTR )|| ( i_send == 0 ) )
{
httpd_connection_t *p_next = p_con->p_next;
httpd_ConnnectionClose( p_httpt, p_con );
p_con = p_next;
+ continue;
}
- else
+ else if( i_send > 0 )
{
- p_con = p_con->p_next;
+ p_con->i_stream_pos += i_send;
}
}
- else
- {
- p_con = p_con->p_next;
- }
+ p_con = p_con->p_next;
continue; /* just for clarity */
}
else
}
} /* for over connection */
-
+#if 0
b_wait = VLC_TRUE;
/* update position for stream based file */
for( i = 0; i < p_httpt->i_file_count; i++ )
}
}
}
+#endif
vlc_mutex_unlock( &p_httpt->file_lock );
- if( b_wait ) msleep( 100 );
+ /*if( b_wait )*/ msleep( 10 );
}
msg_Info( p_httpt, "httpd stopped" );