2006-09-19 19:58:09 +00:00
/*
2006-03-25 23:50:09 +00:00
* Asterisk - - An open source telephony toolkit .
*
* Copyright ( C ) 1999 - 2006 , Digium , Inc .
*
* Mark Spencer < markster @ digium . com >
*
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
* This program is free software , distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2006-03-26 16:48:47 +00:00
/*!
2006-09-19 19:58:09 +00:00
* \ file
2006-04-03 18:38:28 +00:00
* \ brief http server for AMI access
2006-03-26 16:48:47 +00:00
*
2006-04-03 18:38:28 +00:00
* \ author Mark Spencer < markster @ digium . com >
2006-03-26 16:48:47 +00:00
* This program implements a tiny http server supporting the " get " method
2006-09-19 19:58:09 +00:00
* only and was inspired by micro - httpd by Jef Poskanzer
*
2006-04-03 18:38:28 +00:00
* \ ref AstHTTP - AMI over the http protocol
2006-03-26 16:48:47 +00:00
*/
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2006-03-25 23:50:09 +00:00
# include <sys/types.h>
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
# include <time.h>
# include <string.h>
# include <netinet/in.h>
# include <sys/time.h>
# include <sys/socket.h>
2006-04-01 08:49:54 +00:00
# include <sys/stat.h>
2006-03-25 23:50:09 +00:00
# include <sys/signal.h>
# include <arpa/inet.h>
# include <errno.h>
# include <fcntl.h>
# include <pthread.h>
2006-03-26 16:48:47 +00:00
# include "asterisk/cli.h"
# include "asterisk/http.h"
# include "asterisk/utils.h"
# include "asterisk/strings.h"
2006-04-01 08:49:54 +00:00
# include "asterisk/options.h"
# include "asterisk/config.h"
2006-03-25 23:50:09 +00:00
# define MAX_PREFIX 80
2006-04-02 23:55:15 +00:00
# define DEFAULT_PREFIX " / asterisk"
2006-03-25 23:50:09 +00:00
struct ast_http_server_instance {
FILE * f ;
int fd ;
struct sockaddr_in requestor ;
ast_http_callback callback ;
} ;
static struct ast_http_uri * uris ;
static int httpfd = - 1 ;
static pthread_t master = AST_PTHREADT_NULL ;
static char prefix [ MAX_PREFIX ] ;
static int prefix_len = 0 ;
static struct sockaddr_in oldsin ;
2006-04-01 08:49:54 +00:00
static int enablestatic = 0 ;
2006-04-03 18:38:28 +00:00
/*! \brief Limit the kinds of files we're willing to serve up */
2006-04-01 08:49:54 +00:00
static struct {
char * ext ;
char * mtype ;
} mimetypes [ ] = {
{ " png " , " image/png " } ,
{ " jpg " , " image/jpeg " } ,
{ " js " , " application/x-javascript " } ,
{ " wav " , " audio/x-wav " } ,
{ " mp3 " , " audio/mpeg " } ,
} ;
static char * ftype2mtype ( const char * ftype , char * wkspace , int wkspacelen )
{
int x ;
if ( ftype ) {
for ( x = 0 ; x < sizeof ( mimetypes ) / sizeof ( mimetypes [ 0 ] ) ; x + + ) {
if ( ! strcasecmp ( ftype , mimetypes [ x ] . ext ) )
return mimetypes [ x ] . mtype ;
}
}
snprintf ( wkspace , wkspacelen , " text/%s " , ftype ? ftype : " plain " ) ;
return wkspace ;
}
static char * static_callback ( struct sockaddr_in * req , const char * uri , struct ast_variable * vars , int * status , char * * title , int * contentlength )
{
char result [ 4096 ] ;
char * c = result ;
char * path ;
char * ftype , * mtype ;
char wkspace [ 80 ] ;
struct stat st ;
int len ;
int fd ;
void * blob ;
2006-09-19 19:58:09 +00:00
/* Yuck. I'm not really sold on this, but if you don't deliver static content it makes your configuration
2006-04-01 08:49:54 +00:00
substantially more challenging , but this seems like a rather irritating feature creep on Asterisk . */
if ( ! enablestatic | | ast_strlen_zero ( uri ) )
goto out403 ;
/* Disallow any funny filenames at all */
if ( ( uri [ 0 ] < 33 ) | | strchr ( " ./|~@#$%^&*() \t " , uri [ 0 ] ) )
goto out403 ;
if ( strstr ( uri , " /.. " ) )
goto out403 ;
2006-09-19 19:58:09 +00:00
2006-04-01 08:49:54 +00:00
if ( ( ftype = strrchr ( uri , ' . ' ) ) )
ftype + + ;
mtype = ftype2mtype ( ftype , wkspace , sizeof ( wkspace ) ) ;
2006-09-19 19:58:09 +00:00
2006-04-01 08:49:54 +00:00
/* Cap maximum length */
2006-04-15 22:53:53 +00:00
len = strlen ( uri ) + strlen ( ast_config_AST_DATA_DIR ) + strlen ( " /static-http/ " ) + 5 ;
2006-04-01 08:49:54 +00:00
if ( len > 1024 )
goto out403 ;
2006-09-19 19:58:09 +00:00
2006-04-01 08:49:54 +00:00
path = alloca ( len ) ;
2006-04-15 22:53:53 +00:00
sprintf ( path , " %s/static-http/%s " , ast_config_AST_DATA_DIR , uri ) ;
2006-04-01 08:49:54 +00:00
if ( stat ( path , & st ) )
goto out404 ;
if ( S_ISDIR ( st . st_mode ) )
goto out404 ;
fd = open ( path , O_RDONLY ) ;
if ( fd < 0 )
goto out403 ;
2006-09-19 19:58:09 +00:00
2006-04-01 08:49:54 +00:00
len = st . st_size + strlen ( mtype ) + 40 ;
2006-09-19 19:58:09 +00:00
2006-04-01 08:49:54 +00:00
blob = malloc ( len ) ;
if ( blob ) {
c = blob ;
sprintf ( c , " Content-type: %s \r \n \r \n " , mtype ) ;
c + = strlen ( c ) ;
* contentlength = read ( fd , c , st . st_size ) ;
if ( * contentlength < 0 ) {
close ( fd ) ;
free ( blob ) ;
goto out403 ;
}
}
2006-07-18 20:26:38 +00:00
close ( fd ) ;
2006-04-01 08:49:54 +00:00
return blob ;
out404 :
* status = 404 ;
* title = strdup ( " Not Found " ) ;
return ast_http_error ( 404 , " Not Found " , NULL , " Nothing to see here. Move along. " ) ;
out403 :
* status = 403 ;
* title = strdup ( " Access Denied " ) ;
return ast_http_error ( 403 , " Access Denied " , NULL , " Sorry, I cannot let you do that, Dave. " ) ;
}
2006-03-25 23:50:09 +00:00
static char * httpstatus_callback ( struct sockaddr_in * req , const char * uri , struct ast_variable * vars , int * status , char * * title , int * contentlength )
{
char result [ 4096 ] ;
2006-03-26 06:59:10 +00:00
size_t reslen = sizeof ( result ) ;
2006-03-25 23:50:09 +00:00
char * c = result ;
struct ast_variable * v ;
ast_build_string ( & c , & reslen ,
" \r \n "
" <title>Asterisk HTTP Status</title> \r \n "
" <body bgcolor= \" #ffffff \" > \r \n "
" <table bgcolor= \" #f1f1f1 \" align= \" center \" ><tr><td bgcolor= \" #e0e0ff \" colspan= \" 2 \" width= \" 500 \" > \r \n "
" <h2> Asterisk™ HTTP Status</h2></td></tr> \r \n " ) ;
ast_build_string ( & c , & reslen , " <tr><td><i>Prefix</i></td><td><b>%s</b></td></tr> \r \n " , prefix ) ;
ast_build_string ( & c , & reslen , " <tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr> \r \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( oldsin . sin_addr ) ) ;
2006-03-25 23:50:09 +00:00
ast_build_string ( & c , & reslen , " <tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr> \r \n " ,
ntohs ( oldsin . sin_port ) ) ;
ast_build_string ( & c , & reslen , " <tr><td colspan= \" 2 \" ><hr></td></tr> \r \n " ) ;
v = vars ;
while ( v ) {
2006-04-01 08:49:54 +00:00
if ( strncasecmp ( v - > name , " cookie_ " , 7 ) )
ast_build_string ( & c , & reslen , " <tr><td><i>Submitted Variable '%s'</i></td><td>%s</td></tr> \r \n " , v - > name , v - > value ) ;
v = v - > next ;
}
ast_build_string ( & c , & reslen , " <tr><td colspan= \" 2 \" ><hr></td></tr> \r \n " ) ;
v = vars ;
while ( v ) {
if ( ! strncasecmp ( v - > name , " cookie_ " , 7 ) )
ast_build_string ( & c , & reslen , " <tr><td><i>Cookie '%s'</i></td><td>%s</td></tr> \r \n " , v - > name , v - > value ) ;
2006-03-25 23:50:09 +00:00
v = v - > next ;
}
ast_build_string ( & c , & reslen , " </table><center><font size= \" -1 \" ><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body> \r \n " ) ;
return strdup ( result ) ;
}
static struct ast_http_uri statusuri = {
. callback = httpstatus_callback ,
. description = " Asterisk HTTP General Status " ,
. uri = " httpstatus " ,
. has_subtree = 0 ,
} ;
2006-09-19 19:58:09 +00:00
2006-04-01 08:49:54 +00:00
static struct ast_http_uri staticuri = {
. callback = static_callback ,
. description = " Asterisk HTTP Static Delivery " ,
. uri = " static " ,
. has_subtree = 1 ,
} ;
2006-09-19 19:58:09 +00:00
2006-03-25 23:50:09 +00:00
char * ast_http_error ( int status , const char * title , const char * extra_header , const char * text )
{
char * c = NULL ;
asprintf ( & c ,
" Content-type: text/html \r \n "
" %s "
" \r \n "
" <!DOCTYPE HTML PUBLIC \" -//IETF//DTD HTML 2.0//EN \" > \r \n "
" <html><head> \r \n "
" <title>%d %s</title> \r \n "
" </head><body> \r \n "
" <h1>%s</h1> \r \n "
" <p>%s</p> \r \n "
" <hr /> \r \n "
" <address>Asterisk Server</address> \r \n "
" </body></html> \r \n " ,
( extra_header ? extra_header : " " ) , status , title , title , text ) ;
return c ;
}
int ast_http_uri_link ( struct ast_http_uri * urih )
{
struct ast_http_uri * prev = uris ;
if ( ! uris | | strlen ( uris - > uri ) < = strlen ( urih - > uri ) ) {
urih - > next = uris ;
uris = urih ;
} else {
while ( prev - > next & & ( strlen ( prev - > next - > uri ) > strlen ( urih - > uri ) ) )
prev = prev - > next ;
/* Insert it here */
urih - > next = prev - > next ;
prev - > next = urih ;
}
return 0 ;
2006-09-19 19:58:09 +00:00
}
2006-03-25 23:50:09 +00:00
void ast_http_uri_unlink ( struct ast_http_uri * urih )
{
struct ast_http_uri * prev = uris ;
if ( ! uris )
return ;
if ( uris = = urih ) {
uris = uris - > next ;
}
while ( prev - > next ) {
if ( prev - > next = = urih ) {
prev - > next = urih - > next ;
break ;
}
prev = prev - > next ;
}
}
2006-04-01 08:49:54 +00:00
static char * handle_uri ( struct sockaddr_in * sin , char * uri , int * status , char * * title , int * contentlength , struct ast_variable * * cookies )
2006-03-25 23:50:09 +00:00
{
char * c ;
char * turi ;
char * params ;
char * var ;
char * val ;
struct ast_http_uri * urih = NULL ;
int len ;
struct ast_variable * vars = NULL , * v , * prev = NULL ;
2006-09-19 19:58:09 +00:00
2006-03-25 23:50:09 +00:00
params = strchr ( uri , ' ? ' ) ;
if ( params ) {
2006-10-16 06:30:51 +00:00
* params + + = ' \0 ' ;
2006-03-25 23:50:09 +00:00
while ( ( var = strsep ( & params , " & " ) ) ) {
val = strchr ( var , ' = ' ) ;
if ( val ) {
2006-10-16 06:30:51 +00:00
* val + + = ' \0 ' ;
2006-04-01 08:49:54 +00:00
ast_uri_decode ( val ) ;
2006-09-19 19:58:09 +00:00
} else
2006-03-25 23:50:09 +00:00
val = " " ;
ast_uri_decode ( var ) ;
if ( ( v = ast_variable_new ( var , val ) ) ) {
if ( vars )
prev - > next = v ;
else
vars = v ;
prev = v ;
}
}
}
2006-04-01 08:49:54 +00:00
if ( prev )
prev - > next = * cookies ;
else
vars = * cookies ;
* cookies = NULL ;
2006-03-25 23:50:09 +00:00
ast_uri_decode ( uri ) ;
if ( ! strncasecmp ( uri , prefix , prefix_len ) ) {
uri + = prefix_len ;
if ( ! * uri | | ( * uri = = ' / ' ) ) {
if ( * uri = = ' / ' )
uri + + ;
urih = uris ;
while ( urih ) {
len = strlen ( urih - > uri ) ;
if ( ! strncasecmp ( urih - > uri , uri , len ) ) {
if ( ! uri [ len ] | | uri [ len ] = = ' / ' ) {
turi = uri + len ;
if ( * turi = = ' / ' )
turi + + ;
if ( ! * turi | | urih - > has_subtree ) {
uri = turi ;
break ;
}
}
}
urih = urih - > next ;
}
}
}
if ( urih ) {
c = urih - > callback ( sin , uri , vars , status , title , contentlength ) ;
ast_variables_destroy ( vars ) ;
2006-04-02 09:10:43 +00:00
} else if ( ast_strlen_zero ( uri ) & & ast_strlen_zero ( prefix ) ) {
/* Special case: If no prefix, and no URI, send to /static/index.html */
c = ast_http_error ( 302 , " Moved Temporarily " , " Location: /static/index.html \r \n " , " This is not the page you are looking for... " ) ;
* status = 302 ;
* title = strdup ( " Moved Temporarily " ) ;
2006-03-25 23:50:09 +00:00
} else {
2006-10-15 20:37:42 +00:00
c = ast_http_error ( 404 , " Not Found " , NULL , " The requested URL was not found on this server. " ) ;
2006-03-25 23:50:09 +00:00
* status = 404 ;
* title = strdup ( " Not Found " ) ;
}
return c ;
}
static void * ast_httpd_helper_thread ( void * data )
{
char buf [ 4096 ] ;
2006-04-01 08:49:54 +00:00
char cookie [ 4096 ] ;
2006-03-25 23:50:09 +00:00
char timebuf [ 256 ] ;
struct ast_http_server_instance * ser = data ;
2006-04-01 08:49:54 +00:00
struct ast_variable * var , * prev = NULL , * vars = NULL ;
2006-03-25 23:50:09 +00:00
char * uri , * c , * title = NULL ;
2006-04-01 08:49:54 +00:00
char * vname , * vval ;
2006-03-25 23:50:09 +00:00
int status = 200 , contentlength = 0 ;
time_t t ;
if ( fgets ( buf , sizeof ( buf ) , ser - > f ) ) {
2006-10-16 06:30:51 +00:00
uri = ast_skip_nonblanks ( buf ) ; /* Skip method */
if ( * uri )
* uri + + = ' \0 ' ;
2006-03-25 23:50:09 +00:00
2006-10-16 06:30:51 +00:00
uri = ast_skip_blanks ( uri ) ; /* Skip white space */
2006-03-25 23:50:09 +00:00
2006-10-16 06:30:51 +00:00
if ( * uri ) { /* terminate at the first blank */
c = ast_skip_nonblanks ( uri ) ;
if ( * c )
2006-03-25 23:50:09 +00:00
* c = ' \0 ' ;
}
2006-04-01 08:49:54 +00:00
2006-10-16 06:30:51 +00:00
/* process "Cookie: " lines */
2006-04-01 08:49:54 +00:00
while ( fgets ( cookie , sizeof ( cookie ) , ser - > f ) ) {
/* Trim trailing characters */
2006-10-16 06:30:51 +00:00
ast_trim_blanks ( cookie ) ;
2006-04-01 08:49:54 +00:00
if ( ast_strlen_zero ( cookie ) )
break ;
2006-10-16 06:30:51 +00:00
if ( strncasecmp ( cookie , " Cookie: " , 8 ) )
continue ;
/* XXX fix indentation */
2006-08-17 04:26:28 +00:00
2006-10-16 06:55:14 +00:00
/* TODO - The cookie parsing code below seems to work
in IE6 and FireFox 1.5 . However , it is not entirely
correct , and therefore may not work in all
circumstances .
For more details see RFC 2109 and RFC 2965 */
/* FireFox cookie strings look like:
Cookie : mansession_id = " ******** "
InternetExplorer ' s look like :
Cookie : $ Version = " 1 " ; mansession_id = " ******** " */
2006-09-19 19:58:09 +00:00
2006-10-16 06:55:14 +00:00
/* If we got a FireFox cookie string, the name's right
after " Cookie: " */
vname = cookie + 8 ;
2006-09-19 19:58:09 +00:00
2006-10-16 06:55:14 +00:00
/* If we got an IE cookie string, we need to skip to
past the version to get to the name */
if ( * vname = = ' $ ' ) {
vname = strchr ( vname , ' ; ' ) ;
if ( vname ) {
vname + + ;
if ( * vname = = ' ' )
2006-08-17 04:26:28 +00:00
vname + + ;
}
2006-10-16 06:55:14 +00:00
}
2006-09-19 19:58:09 +00:00
2006-10-16 06:55:14 +00:00
if ( vname ) {
vval = strchr ( vname , ' = ' ) ;
if ( vval ) {
/* Ditch the = and the quotes */
* vval + + = ' \0 ' ;
if ( * vval )
vval + + ;
if ( strlen ( vval ) )
vval [ strlen ( vval ) - 1 ] = ' \0 ' ;
var = ast_variable_new ( vname , vval ) ;
if ( var ) {
if ( prev )
prev - > next = var ;
else
vars = var ;
prev = var ;
2006-04-01 08:49:54 +00:00
}
}
2006-10-16 06:55:14 +00:00
}
2006-04-01 08:49:54 +00:00
}
2006-03-25 23:50:09 +00:00
if ( * uri ) {
2006-09-19 19:58:09 +00:00
if ( ! strcasecmp ( buf , " get " ) )
2006-04-01 08:49:54 +00:00
c = handle_uri ( & ser - > requestor , uri , & status , & title , & contentlength , & vars ) ;
2006-09-19 19:58:09 +00:00
else
2006-03-25 23:50:09 +00:00
c = ast_http_error ( 501 , " Not Implemented " , NULL , " Attempt to use unimplemented / unsupported method " ) ; \
2006-09-19 19:58:09 +00:00
} else
2006-03-25 23:50:09 +00:00
c = ast_http_error ( 400 , " Bad Request " , NULL , " Invalid Request " ) ;
2006-04-01 08:49:54 +00:00
/* If they aren't mopped up already, clean up the cookies */
if ( vars )
ast_variables_destroy ( vars ) ;
2006-03-25 23:50:09 +00:00
if ( ! c )
c = ast_http_error ( 500 , " Internal Error " , NULL , " Internal Server Error " ) ;
if ( c ) {
time ( & t ) ;
strftime ( timebuf , sizeof ( timebuf ) , " %a, %d %b %Y %H:%M:%S GMT " , gmtime ( & t ) ) ;
2006-04-01 08:49:54 +00:00
ast_cli ( ser - > fd , " HTTP/1.1 %d %s \r \n " , status , title ? title : " OK " ) ;
2006-03-25 23:50:09 +00:00
ast_cli ( ser - > fd , " Server: Asterisk \r \n " ) ;
ast_cli ( ser - > fd , " Date: %s \r \n " , timebuf ) ;
ast_cli ( ser - > fd , " Connection: close \r \n " ) ;
2006-04-01 08:49:54 +00:00
if ( contentlength ) {
char * tmp ;
tmp = strstr ( c , " \r \n \r \n " ) ;
if ( tmp ) {
ast_cli ( ser - > fd , " Content-length: %d \r \n " , contentlength ) ;
write ( ser - > fd , c , ( tmp + 4 - c ) ) ;
write ( ser - > fd , tmp + 4 , contentlength ) ;
}
} else
ast_cli ( ser - > fd , " %s " , c ) ;
2006-03-25 23:50:09 +00:00
free ( c ) ;
}
if ( title )
free ( title ) ;
}
fclose ( ser - > f ) ;
free ( ser ) ;
return NULL ;
}
static void * http_root ( void * data )
{
int fd ;
struct sockaddr_in sin ;
2006-07-07 06:57:02 +00:00
socklen_t sinlen ;
2006-03-25 23:50:09 +00:00
struct ast_http_server_instance * ser ;
pthread_t launched ;
2006-04-02 23:55:15 +00:00
pthread_attr_t attr ;
2006-09-19 19:58:09 +00:00
2006-03-25 23:50:09 +00:00
for ( ; ; ) {
2006-10-15 20:54:15 +00:00
int flags ;
2006-03-25 23:50:09 +00:00
ast_wait_for_input ( httpfd , - 1 ) ;
sinlen = sizeof ( sin ) ;
fd = accept ( httpfd , ( struct sockaddr * ) & sin , & sinlen ) ;
if ( fd < 0 ) {
if ( ( errno ! = EAGAIN ) & & ( errno ! = EINTR ) )
ast_log ( LOG_WARNING , " Accept failed: %s \n " , strerror ( errno ) ) ;
continue ;
}
2006-04-01 08:49:54 +00:00
ser = ast_calloc ( 1 , sizeof ( * ser ) ) ;
2006-10-15 20:54:15 +00:00
if ( ! ser ) {
ast_log ( LOG_WARNING , " No memory for new session: %s \n " , strerror ( errno ) ) ;
close ( fd ) ;
continue ;
}
flags = fcntl ( fd , F_GETFL ) ;
fcntl ( fd , F_SETFL , flags & ~ O_NONBLOCK ) ;
ser - > fd = fd ;
memcpy ( & ser - > requestor , & sin , sizeof ( ser - > requestor ) ) ;
if ( ( ser - > f = fdopen ( ser - > fd , " w+ " ) ) ) {
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
if ( ast_pthread_create_background ( & launched , & attr , ast_httpd_helper_thread , ser ) ) {
ast_log ( LOG_WARNING , " Unable to launch helper thread: %s \n " , strerror ( errno ) ) ;
fclose ( ser - > f ) ;
2006-03-25 23:50:09 +00:00
free ( ser ) ;
}
2006-10-15 20:54:15 +00:00
} else {
ast_log ( LOG_WARNING , " fdopen failed! \n " ) ;
close ( ser - > fd ) ;
free ( ser ) ;
2006-03-25 23:50:09 +00:00
}
}
return NULL ;
}
2006-04-03 18:38:28 +00:00
char * ast_http_setcookie ( const char * var , const char * val , int expires , char * buf , size_t buflen )
2006-04-01 08:49:54 +00:00
{
char * c ;
c = buf ;
ast_build_string ( & c , & buflen , " Set-Cookie: %s= \" %s \" ; Version= \" 1 \" " , var , val ) ;
if ( expires )
ast_build_string ( & c , & buflen , " ; Max-Age=%d " , expires ) ;
ast_build_string ( & c , & buflen , " \r \n " ) ;
return buf ;
}
2006-03-25 23:50:09 +00:00
static void http_server_start ( struct sockaddr_in * sin )
{
int flags ;
int x = 1 ;
2006-09-19 19:58:09 +00:00
2006-03-25 23:50:09 +00:00
/* Do nothing if nothing has changed */
if ( ! memcmp ( & oldsin , sin , sizeof ( oldsin ) ) ) {
2006-10-03 15:53:07 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Nothing changed in http \n " ) ;
2006-03-25 23:50:09 +00:00
return ;
}
2006-09-19 19:58:09 +00:00
2006-03-25 23:50:09 +00:00
memcpy ( & oldsin , sin , sizeof ( oldsin ) ) ;
2006-09-19 19:58:09 +00:00
2006-03-25 23:50:09 +00:00
/* Shutdown a running server if there is one */
if ( master ! = AST_PTHREADT_NULL ) {
pthread_cancel ( master ) ;
pthread_kill ( master , SIGURG ) ;
pthread_join ( master , NULL ) ;
}
2006-09-19 19:58:09 +00:00
2006-03-25 23:50:09 +00:00
if ( httpfd ! = - 1 )
close ( httpfd ) ;
/* If there's no new server, stop here */
if ( ! sin - > sin_family )
return ;
2006-09-19 19:58:09 +00:00
2006-03-25 23:50:09 +00:00
httpfd = socket ( AF_INET , SOCK_STREAM , 0 ) ;
if ( httpfd < 0 ) {
ast_log ( LOG_WARNING , " Unable to allocate socket: %s \n " , strerror ( errno ) ) ;
return ;
}
2006-09-19 19:58:09 +00:00
2006-03-25 23:50:09 +00:00
setsockopt ( httpfd , SOL_SOCKET , SO_REUSEADDR , & x , sizeof ( x ) ) ;
if ( bind ( httpfd , ( struct sockaddr * ) sin , sizeof ( * sin ) ) ) {
ast_log ( LOG_NOTICE , " Unable to bind http server to %s:%d: %s \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( sin - > sin_addr ) , ntohs ( sin - > sin_port ) ,
2006-03-25 23:50:09 +00:00
strerror ( errno ) ) ;
close ( httpfd ) ;
httpfd = - 1 ;
return ;
}
if ( listen ( httpfd , 10 ) ) {
ast_log ( LOG_NOTICE , " Unable to listen! \n " ) ;
close ( httpfd ) ;
httpfd = - 1 ;
return ;
}
flags = fcntl ( httpfd , F_GETFL ) ;
fcntl ( httpfd , F_SETFL , flags | O_NONBLOCK ) ;
2006-10-04 19:51:38 +00:00
if ( ast_pthread_create_background ( & master , NULL , http_root , NULL ) ) {
2006-03-25 23:50:09 +00:00
ast_log ( LOG_NOTICE , " Unable to launch http server on %s:%d: %s \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( sin - > sin_addr ) , ntohs ( sin - > sin_port ) ,
2006-03-25 23:50:09 +00:00
strerror ( errno ) ) ;
close ( httpfd ) ;
httpfd = - 1 ;
}
}
static int __ast_http_load ( int reload )
{
struct ast_config * cfg ;
struct ast_variable * v ;
int enabled = 0 ;
2006-04-01 08:49:54 +00:00
int newenablestatic = 0 ;
2006-03-25 23:50:09 +00:00
struct sockaddr_in sin ;
struct hostent * hp ;
struct ast_hostent ahp ;
char newprefix [ MAX_PREFIX ] ;
2006-04-03 18:38:28 +00:00
2006-03-25 23:50:09 +00:00
memset ( & sin , 0 , sizeof ( sin ) ) ;
sin . sin_port = 8088 ;
strcpy ( newprefix , DEFAULT_PREFIX ) ;
cfg = ast_config_load ( " http.conf " ) ;
if ( cfg ) {
v = ast_variable_browse ( cfg , " general " ) ;
while ( v ) {
if ( ! strcasecmp ( v - > name , " enabled " ) )
enabled = ast_true ( v - > value ) ;
2006-04-01 08:49:54 +00:00
else if ( ! strcasecmp ( v - > name , " enablestatic " ) )
newenablestatic = ast_true ( v - > value ) ;
2006-03-25 23:50:09 +00:00
else if ( ! strcasecmp ( v - > name , " bindport " ) )
sin . sin_port = ntohs ( atoi ( v - > value ) ) ;
else if ( ! strcasecmp ( v - > name , " bindaddr " ) ) {
if ( ( hp = ast_gethostbyname ( v - > value , & ahp ) ) ) {
memcpy ( & sin . sin_addr , hp - > h_addr , sizeof ( sin . sin_addr ) ) ;
} else {
ast_log ( LOG_WARNING , " Invalid bind address '%s' \n " , v - > value ) ;
}
2006-04-02 09:10:43 +00:00
} else if ( ! strcasecmp ( v - > name , " prefix " ) ) {
if ( ! ast_strlen_zero ( v - > value ) ) {
newprefix [ 0 ] = ' / ' ;
ast_copy_string ( newprefix + 1 , v - > value , sizeof ( newprefix ) - 1 ) ;
} else {
newprefix [ 0 ] = ' \0 ' ;
}
2006-09-19 19:58:09 +00:00
2006-04-02 09:10:43 +00:00
}
2006-03-25 23:50:09 +00:00
v = v - > next ;
}
ast_config_destroy ( cfg ) ;
}
if ( enabled )
sin . sin_family = AF_INET ;
if ( strcmp ( prefix , newprefix ) ) {
ast_copy_string ( prefix , newprefix , sizeof ( prefix ) ) ;
prefix_len = strlen ( prefix ) ;
}
2006-04-01 08:49:54 +00:00
enablestatic = newenablestatic ;
2006-03-25 23:50:09 +00:00
http_server_start ( & sin ) ;
return 0 ;
}
static int handle_show_http ( int fd , int argc , char * argv [ ] )
{
struct ast_http_uri * urih ;
2006-04-14 04:59:11 +00:00
if ( argc ! = 3 )
2006-03-25 23:50:09 +00:00
return RESULT_SHOWUSAGE ;
ast_cli ( fd , " HTTP Server Status: \n " ) ;
ast_cli ( fd , " Prefix: %s \n " , prefix ) ;
if ( oldsin . sin_family )
ast_cli ( fd , " Server Enabled and Bound to %s:%d \n \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( oldsin . sin_addr ) ,
2006-03-25 23:50:09 +00:00
ntohs ( oldsin . sin_port ) ) ;
else
ast_cli ( fd , " Server Disabled \n \n " ) ;
ast_cli ( fd , " Enabled URI's: \n " ) ;
urih = uris ;
while ( urih ) {
2006-04-02 09:10:43 +00:00
ast_cli ( fd , " %s/%s%s => %s \n " , prefix , urih - > uri , ( urih - > has_subtree ? " /... " : " " ) , urih - > description ) ;
2006-03-25 23:50:09 +00:00
urih = urih - > next ;
}
if ( ! uris )
ast_cli ( fd , " None. \n " ) ;
return RESULT_SUCCESS ;
}
int ast_http_reload ( void )
{
return __ast_http_load ( 1 ) ;
}
static char show_http_help [ ] =
2006-09-18 19:54:18 +00:00
" Usage: http list status \n "
" Lists status of internal HTTP engine \n " ;
static struct ast_cli_entry cli_http [ ] = {
{ { " http " , " list " , " status " , NULL } ,
handle_show_http , " Display HTTP server status " ,
2006-09-21 21:17:39 +00:00
show_http_help } ,
2006-03-25 23:50:09 +00:00
} ;
int ast_http_init ( void )
{
ast_http_uri_link ( & statusuri ) ;
2006-04-01 08:49:54 +00:00
ast_http_uri_link ( & staticuri ) ;
2006-09-18 19:54:18 +00:00
ast_cli_register_multiple ( cli_http , sizeof ( cli_http ) / sizeof ( struct ast_cli_entry ) ) ;
2006-03-25 23:50:09 +00:00
return __ast_http_load ( 0 ) ;
}