Commit 84aaa859 authored by Laurent Aimar's avatar Laurent Aimar

* modules/access_output/http : http output.

 * httpd : mini http server (be carefull about security issue...)
parent 4d12c66c
/*****************************************************************************
* httpd.h
*****************************************************************************
* Copyright (C) 2001-2003 VideoLAN
* $Id: httpd.h,v 1.1 2003/02/23 19:05:22 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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.
*****************************************************************************/
typedef struct httpd_t httpd_t;
typedef struct httpd_host_t httpd_host_t;
typedef struct httpd_file_t httpd_file_t;
//typedef struct httpd_stream_t httpd_stream_t;
typedef httpd_file_t httpd_stream_t;
typedef struct httpd_file_callback_args_t httpd_file_callback_args_t;
typedef int (*httpd_file_callback)( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data );
typedef struct httpd_sys_t httpd_sys_t;
struct httpd_t
{
VLC_COMMON_MEMBERS
module_t *p_module;
httpd_sys_t *p_sys;
httpd_host_t *(*pf_register_host) ( httpd_t *, char *, int );
void (*pf_unregister_host) ( httpd_t *, httpd_host_t * );
httpd_file_t *(*pf_register_file) ( 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 );
void (*pf_unregister_file) ( httpd_t *, httpd_file_t * );
httpd_stream_t *(*pf_register_stream) ( httpd_t *,
char *psz_file, char *psz_mime,
char *psz_user, char *psz_password );
int (*pf_send_stream) ( httpd_t *,
httpd_stream_t *,
uint8_t *, int );
void (*pf_unregister_stream) ( httpd_t *, httpd_stream_t * );
};
/*
* httpd_Find:
*
* Return the running httpd instance
* (if none and b_create then a new one is created)
*/
static inline httpd_t* httpd_Find( vlc_object_t *p_this, vlc_bool_t b_create )
{
httpd_t *p_httpd = NULL;
p_httpd = vlc_object_find( p_this, VLC_OBJECT_HTTPD, FIND_ANYWHERE );
if( !p_httpd )
{
if( !b_create )
{
return( NULL );
}
p_httpd = vlc_object_create( p_this, VLC_OBJECT_HTTPD );
if( !p_httpd )
{
msg_Err( p_this, "out of memory" );
return( NULL );
}
p_httpd->p_module = module_Need( p_httpd, "httpd", "" );
if( !p_httpd->p_module )
{
msg_Err( p_this, "no suitable httpd module" );
vlc_object_destroy( p_httpd );
return( NULL );
}
vlc_object_yield( p_httpd );
}
return( p_httpd );
}
static inline void httpd_Release( httpd_t *p_httpd )
{
vlc_object_release( p_httpd );
}
/*****************************************************************************
* http.c
*****************************************************************************
* Copyright (C) 2001-2003 VideoLAN
* $Id: http.c,v 1.1 2003/02/23 19:05:22 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/sout.h>
#include "httpd.h"
#define FREE( p ) if( p ) { free( p); (p) = NULL; }
#define DEFAULT_PORT 8080
/*****************************************************************************
* Exported prototypes
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static int Write( sout_access_out_t *, sout_buffer_t * );
static int Seek ( sout_access_out_t *, off_t );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("HTTP stream ouput") );
set_capability( "sout access", 0 );
add_shortcut( "http" );
set_callbacks( Open, Close );
vlc_module_end();
struct sout_access_out_sys_t
{
httpd_t *p_httpd;
/* host */
httpd_host_t *p_httpd_host;
/* stream */
httpd_stream_t *p_httpd_stream;
};
/*****************************************************************************
* Open: open the file
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
sout_access_out_t *p_access = (sout_access_out_t*)p_this;
sout_access_out_sys_t *p_sys;
char *psz_parser, *psz_name;
char *psz_bind_addr;
int i_bind_port;
char *psz_file_name;
if( !( p_sys = p_access->p_sys =
malloc( sizeof( sout_access_out_sys_t ) ) ) )
{
msg_Err( p_access, "Not enough memory" );
return( VLC_EGENERIC );
}
/* *** parse p_access->psz_name to extract bind address, port and file name *** */
/* p_access->psz_name host.name:port/filename */
psz_name = psz_parser = strdup( p_access->psz_name );
psz_bind_addr = psz_parser;
i_bind_port = 0;
psz_file_name = "";
while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' )
{
psz_parser++;
}
if( *psz_parser == ':' )
{
*psz_parser = '\0';
psz_parser++;
i_bind_port = atoi( psz_parser );
while( *psz_parser && *psz_parser != '/' )
{
psz_parser++;
}
}
if( *psz_parser == '/' )
{
*psz_parser = '\0';
psz_parser++;
psz_file_name = psz_parser;
}
if( i_bind_port <= 0 )
{
i_bind_port = DEFAULT_PORT;
}
if( !*psz_file_name )
{
psz_file_name = strdup( "/" );
}
else if( *psz_file_name != '/' )
{
char *p = psz_file_name;
psz_file_name = malloc( strlen( p ) + 2 );
strcpy( psz_file_name, "/" );
strcat( psz_file_name, p );
}
p_sys->p_httpd = httpd_Find( VLC_OBJECT(p_access), VLC_TRUE );
if( !p_sys->p_httpd )
{
msg_Err( p_access, "cannot start httpd daemon" );
free( psz_name );
free( psz_file_name );
free( p_access );
return( VLC_EGENERIC );
}
p_sys->p_httpd_host =
p_sys->p_httpd->pf_register_host( p_sys->p_httpd,
psz_bind_addr, i_bind_port );
if( !p_sys->p_httpd_host )
{
msg_Err( p_access, "cannot listen on %s:%d", psz_bind_addr, i_bind_port );
httpd_Release( p_sys->p_httpd );
free( psz_name );
free( psz_file_name );
free( p_access );
return( VLC_EGENERIC );
}
p_sys->p_httpd_stream =
p_sys->p_httpd->pf_register_stream( p_sys->p_httpd,
psz_file_name, "application/x-octet_stream",
NULL, NULL );
if( !p_sys->p_httpd_stream )
{
msg_Err( p_access, "cannot add stream %s", psz_file_name );
p_sys->p_httpd->pf_unregister_host( p_sys->p_httpd, p_sys->p_httpd_host );
httpd_Release( p_sys->p_httpd );
free( psz_name );
free( psz_file_name );
free( p_access );
return( VLC_EGENERIC );
}
p_access->pf_write = Write;
p_access->pf_seek = Seek;
return VLC_SUCCESS;
}
/*****************************************************************************
* Close: close the target
*****************************************************************************/
static void Close( vlc_object_t * p_this )
{
sout_access_out_t *p_access = (sout_access_out_t*)p_this;
sout_access_out_sys_t *p_sys = p_access->p_sys;
p_sys->p_httpd->pf_unregister_stream( p_sys->p_httpd, p_sys->p_httpd_stream );
p_sys->p_httpd->pf_unregister_host( p_sys->p_httpd, p_sys->p_httpd_host );
httpd_Release( p_sys->p_httpd );
msg_Info( p_access, "Close" );
free( p_sys );
}
/*****************************************************************************
* Write:
*****************************************************************************/
static int Write( sout_access_out_t *p_access, sout_buffer_t *p_buffer )
{
sout_access_out_sys_t *p_sys = p_access->p_sys;
int i_err = 0;
while( p_buffer )
{
sout_buffer_t *p_next;
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 );
p_next = p_buffer->p_next;
sout_BufferDelete( p_access->p_sout, p_buffer );
p_buffer = p_next;
if( i_err < 0 )
{
break;
}
}
if( i_err < 0 )
{
sout_buffer_t *p_next;
while( p_buffer )
{
p_next = p_buffer->p_next;
sout_BufferDelete( p_access->p_sout, p_buffer );
p_buffer = p_next;
}
}
return( i_err < 0 ? VLC_EGENERIC : VLC_SUCCESS );
}
/*****************************************************************************
* Seek: seek to a specific location in a file
*****************************************************************************/
static int Seek( sout_access_out_t *p_access, off_t i_pos )
{
msg_Err( p_access, "http sout access cannot seek" );
return( VLC_EGENERIC );
}
/*****************************************************************************
* httpd.c
*****************************************************************************
* Copyright (C) 2001-2003 VideoLAN
* $Id: httpd.c,v 1.1 2003/02/23 19:05:22 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <vlc/vlc.h>
#include "httpd.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
# include <io.h>
#endif
#if defined( UNDER_CE )
# include <winsock.h>
#elif defined( WIN32 )
# include <winsock2.h>
# include <ws2tcpip.h>
# ifndef IN_MULTICAST
# define IN_MULTICAST(a) IN_CLASSD(a)
# endif
#else
# include <netdb.h> /* hostent ... */
# include <sys/socket.h>
# include <netinet/in.h>
# ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h> /* inet_ntoa(), inet_aton() */
# endif
#endif
#include "network.h"
#ifndef INADDR_ANY
# define INADDR_ANY 0x00000000
#endif
#ifndef INADDR_NONE
# define INADDR_NONE 0xFFFFFFFF
#endif
#define LISTEN_BACKLOG 100
#define HTTPD_MAX_CONNECTION 1024
#define FREE( p ) if( p ) { free( p); (p) = NULL; }
#if defined( WIN32 ) || defined( UNDER_CE )
#define SOCKET_CLOSE closesocket;
#else
#define SOCKET_CLOSE close
#endif
/*****************************************************************************
* Exported prototypes
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("HTTP 1.0 daemon") );
set_capability( "httpd", 42 );
set_callbacks( Open, Close );
vlc_module_end();
/*****************************************************************************
* Prototypes
*****************************************************************************/
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 * );
//#define httpd_stream_t httpd_file_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 void UnregisterStream( httpd_t *, httpd_stream_t* );
/*****************************************************************************
* Internal definitions
*****************************************************************************/
struct httpd_host_t
{
int i_ref;
char *psz_host_addr;
int i_port;
struct sockaddr_in sock;
int fd;
};
#define HTTPD_AUTHENTICATE_NONE 0
#define HTTPD_AUTHENTICATE_BASIC 1
//typedef httpd_file_t httpd_stream_t;
struct httpd_file_t
{
int i_ref;
char *psz_file;
char *psz_mime;
int i_authenticate_method;
char *psz_user; /* NULL if no auth */
char *psz_password; /* NULL if no auth */
vlc_bool_t b_stream; /* if false: httpd will retreive data by a callback
true: it's up to the program to give data to httpd */
void *p_sys; /* provided for user */
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 */
};
#define HTTPD_CONNECTION_RECEIVING_REQUEST 1
#define HTTPD_CONNECTION_SENDING_HEADER 2
#define HTTPD_CONNECTION_SENDING_FILE 3
#define HTTPD_CONNECTION_SENDING_STREAM 4
typedef struct httpd_connection_s
{
struct httpd_connection_s *p_next;
struct httpd_connection_s *p_prev;
struct sockaddr_in sock;
int fd;
int i_state;
char *psz_file; // file to be send
int i_http_error; // error to be send with the file
char *psz_user; // if Authorization in the request header
char *psz_password;
httpd_file_t *p_file;
int i_buffer_size;
uint8_t *p_buffer;
int i_buffer; /* private */
} httpd_connection_t;
/*
* The httpd thread
*/
struct httpd_sys_t
{
VLC_COMMON_MEMBERS
vlc_mutex_t host_lock;
volatile int i_host_count;
httpd_host_t **host;
vlc_mutex_t file_lock;
int i_file_count;
httpd_file_t **file;
vlc_mutex_t connection_lock;
int i_connection_count;
httpd_connection_t *p_first_connection;
};
static void httpd_Thread( httpd_sys_t *p_httpt );
static void httpd_ConnnectionNew( httpd_sys_t *, int , struct sockaddr_in * );
static void httpd_ConnnectionClose( httpd_sys_t *, httpd_connection_t * );
/*****************************************************************************
* Open:
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
httpd_t *p_httpd = (httpd_t*)p_this;
httpd_sys_t *p_httpt;
/* Launch httpt thread */
if( !( p_httpt = vlc_object_create( p_this, sizeof( httpd_sys_t ) ) ) )
{
msg_Err( p_this, "out of memory" );
return( VLC_EGENERIC );
}
p_httpt->b_die = 0;
p_httpt->b_error= 0;
/* init httpt_t structure */
vlc_mutex_init( p_httpd, &p_httpt->host_lock );
p_httpt->i_host_count = 0;
p_httpt->host = NULL;
vlc_mutex_init( p_httpd, &p_httpt->file_lock );
p_httpt->i_file_count = 0;
p_httpt->file = NULL;
vlc_mutex_init( p_httpd, &p_httpt->connection_lock );
p_httpt->i_connection_count = 0;
p_httpt->p_first_connection = NULL;
/* start the thread */
if( vlc_thread_create( p_httpt, "httpd thread",
httpd_Thread, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
{
msg_Err( p_this, "cannot spawn http thread" );
vlc_mutex_destroy( &p_httpt->host_lock );
vlc_mutex_destroy( &p_httpt->file_lock );
vlc_mutex_destroy( &p_httpt->connection_lock );
vlc_object_destroy( p_httpt );
return( VLC_EGENERIC );
}
msg_Info( p_httpd, "http thread launched" );
p_httpd->p_sys = p_httpt;
p_httpd->pf_register_host = RegisterHost;
p_httpd->pf_unregister_host = UnregisterHost;
p_httpd->pf_register_file = RegisterFile;
p_httpd->pf_unregister_file = UnregisterFile;
p_httpd->pf_register_stream = RegisterStream;
p_httpd->pf_send_stream = SendStream;
p_httpd->pf_unregister_stream=UnregisterStream;
return( VLC_SUCCESS );