X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fhttpd.c;h=5e7f66c580cd7b8272b4980e8cb9235ddac2b9bb;hb=3de41d49fdd787ce5114372b637dcacc73cdabad;hp=c15c1c115df6ac90b5ead449f47d6e1f9ab3a31b;hpb=0943126a379dde3418a5c536aa65c7ade4f266dc;p=vlc diff --git a/src/misc/httpd.c b/src/misc/httpd.c index c15c1c115d..5e7f66c580 100644 --- a/src/misc/httpd.c +++ b/src/misc/httpd.c @@ -1,11 +1,11 @@ /***************************************************************************** * httpd.c ***************************************************************************** - * Copyright (C) 2004-2005 VideoLAN + * Copyright (C) 2004-2005 the VideoLAN team * $Id$ * * Authors: Laurent Aimar - * Remi Denis-Courmont + * Rémi Denis-Courmont * * 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 @@ -50,22 +50,13 @@ #else # include /* hostent ... */ # include +/* FIXME: should not be needed */ # include # ifdef HAVE_ARPA_INET_H # include /* inet_ntoa(), inet_aton() */ # endif #endif -#if defined(WIN32) && !defined(UNDER_CE) -static const struct in6_addr in6addr_any = {{IN6ADDR_ANY_INIT}}; -#elif defined(UNDER_CE) && defined(AF_INET6) -# undef AF_INET6 -#endif - -#ifndef PF_INET -# define PF_INET AF_INET /* BeOS */ -#endif - #if 0 typedef struct httpd_t httpd_t; @@ -217,9 +208,9 @@ struct httpd_host_t int i_ref; /* address/port and socket for listening at connections */ - struct sockaddr_storage sock; - int i_sock_size; - int fd; + char *psz_hostname; + int i_port; + int *fd; vlc_mutex_t lock; @@ -246,6 +237,8 @@ struct httpd_url_t char *psz_url; char *psz_user; char *psz_password; + char **ppsz_hosts; + int i_hosts; struct { @@ -473,7 +466,7 @@ static int httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, if( query->i_type != HTTPD_MSG_HEAD ) { - char *psz_args = query->psz_args; + uint8_t *psz_args = query->psz_args; if( query->i_type == HTTPD_MSG_POST ) { /* Check that */ @@ -498,13 +491,15 @@ static int httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_file_t *httpd_FileNew( httpd_host_t *host, char *psz_url, char *psz_mime, char *psz_user, char *psz_password, + char **ppsz_hosts, int i_hosts, httpd_file_callback_t pf_fill, httpd_file_sys_t *p_sys ) { httpd_file_t *file = malloc( sizeof( httpd_file_t ) ); if( ( file->url = httpd_UrlNewUnique( host, psz_url, psz_user, - psz_password ) ) == NULL ) + psz_password, ppsz_hosts, i_hosts ) + ) == NULL ) { free( file ); return NULL; @@ -595,7 +590,8 @@ httpd_redirect_t *httpd_RedirectNew( httpd_host_t *host, char *psz_url_dst, { httpd_redirect_t *rdir = malloc( sizeof( httpd_redirect_t ) ); - if( !( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL ) ) ) + if( !( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL, + NULL, 0 ) ) ) { free( rdir ); return NULL; @@ -770,12 +766,14 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys, httpd_stream_t *httpd_StreamNew( httpd_host_t *host, char *psz_url, char *psz_mime, - char *psz_user, char *psz_password ) + char *psz_user, char *psz_password, + char **ppsz_hosts, int i_hosts ) { httpd_stream_t *stream = malloc( sizeof( httpd_stream_t ) ); if( ( stream->url = httpd_UrlNewUnique( host, psz_url, psz_user, - psz_password ) ) == NULL ) + psz_password, ppsz_hosts, i_hosts ) + ) == NULL ) { free( stream ); return NULL; @@ -877,122 +875,35 @@ void httpd_StreamDelete( httpd_stream_t *stream ) /***************************************************************************** * Low level *****************************************************************************/ -#define LISTEN_BACKLOG 100 - -#if defined(HAVE_GETNAMEINFO) && !defined(HAVE_GETADDRINFO) -/* - * For now, VLC's configure script does not check for getaddrinfo(), - * but it should be present if getnameinfo() is (the opposite is untrue, with - * Debian potato as an example) - */ -# define HAVE_GETADDRINFO 1 -#endif - static void httpd_HostThread( httpd_host_t * ); -static int GetAddrPort( const struct sockaddr_storage *p_ss ); - -#ifndef HAVE_GETADDRINFO -struct httpd_addrinfo -{ - int ai_family; - int ai_socktype; - int ai_protocol; - /*int ai_flags;*/ - struct sockaddr *ai_addr; - int ai_addrlen; - struct httpd_addrinfo *ai_next; -}; -# define addrinfo httpd_addrinfo - -static int BuildAddr( struct sockaddr_in * p_socket, - const char * psz_address, int i_port ); -#endif - /* create a new host */ -httpd_host_t *httpd_HostNew( vlc_object_t *p_this, char *psz_host, +httpd_host_t *httpd_HostNew( vlc_object_t *p_this, const char *psz_host, int i_port ) { - return httpd_TLSHostNew( p_this, psz_host, i_port, NULL ); + return httpd_TLSHostNew( p_this, psz_host, i_port, NULL, NULL, NULL, NULL + ); } -httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, char *psz_host, - int i_port, tls_server_t *p_tls ) +httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, const char *psz_hostname, + int i_port, + const char *psz_cert, const char *psz_key, + const char *psz_ca, const char *psz_crl ) { httpd_t *httpd; - httpd_host_t *host = NULL; - vlc_value_t lockval; - int fd = -1; - struct addrinfo *res, *ptr; - - /* resolv */ -#ifdef HAVE_GETADDRINFO - { - vlc_value_t val; - char psz_port[6]; - struct addrinfo hints; - - memset( &hints, 0, sizeof( hints ) ); - -#if 0 - /* - * For now, keep IPv4 by default. That said, it should be safe to use - * IPv6 by default *on the server side*, as, apart from NetBSD, most - * systems accept IPv4 clients on IPv6 listening sockets. - */ - hints.ai_family = PF_INET; -#else - hints.ai_family = 0; - - /* Check if ipv4 or ipv6 were forced */ - var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); - var_Get( p_this, "ipv4", &val ); - if( val.b_bool ) - hints.ai_family = PF_INET; -#endif - var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); - var_Get( p_this, "ipv6", &val ); - if( val.b_bool ) - hints.ai_family = PF_INET6; - - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - - if (*psz_host == '\0') - psz_host = NULL; - - snprintf( psz_port, sizeof( psz_port ), "%d", i_port ); - psz_port[sizeof( psz_port ) - 1] = '\0'; - - if( getaddrinfo( psz_host, psz_port, &hints, &res ) ) - { - msg_Err( p_this, "cannot resolve %s:%d", psz_host, i_port ); - return NULL; - } - } - -#else - struct sockaddr_in sock; - struct httpd_addrinfo info; - - info.ai_family = PF_INET; - info.ai_socktype = SOCK_STREAM; - info.ai_protocol = 0; - info.ai_addr = (struct sockaddr *)&sock; - info.ai_addrlen = sizeof( sock ); - info.ai_next = NULL; - - res = &info; + httpd_host_t *host; + tls_server_t *p_tls; + char *psz_host; + vlc_value_t lockval; + int i; - if( BuildAddr( &sock, psz_host, i_port ) ) + psz_host = strdup( psz_hostname ); + if( psz_host == NULL ) { - msg_Err( p_this, "cannot build address for %s:%d", psz_host, i_port ); + msg_Err( p_this, "memory error" ); return NULL; } -# define freeaddrinfo( r ) (void)0; -#endif - /* to be sure to avoid multiple creation */ var_Create( p_this->p_libvlc, "httpd_mutex", VLC_VAR_MUTEX ); var_Get( p_this->p_libvlc, "httpd_mutex", &lockval ); @@ -1004,7 +915,7 @@ httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, char *psz_host, if( ( httpd = vlc_object_create( p_this, VLC_OBJECT_HTTPD ) ) == NULL ) { vlc_mutex_unlock( lockval.p_address ); - freeaddrinfo( res ); + free( psz_host ); return NULL; } @@ -1015,159 +926,72 @@ httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, char *psz_host, vlc_object_attach( httpd, p_this->p_vlc ); } - for( ptr = res; (ptr != NULL) && (fd == -1); ptr = ptr->ai_next ) + /* verify if it already exist */ + for( i = httpd->i_host - 1; i >= 0; i-- ) { - int i; + host = httpd->host[i]; - if( ((unsigned)ptr->ai_addrlen) > sizeof( struct sockaddr_storage ) ) - { - msg_Dbg( p_this, "socket address too big" ); + /* cannot mix TLS and non-TLS hosts */ + if( ( ( httpd->host[i]->p_tls != NULL ) != ( psz_cert != NULL ) ) + || ( host->i_port != i_port ) + || strcmp( host->psz_hostname, psz_hostname ) ) continue; - } - - /* verify if it already exist */ - for( i = 0; i < httpd->i_host; i++ ) - { - if( GetAddrPort (&httpd->host[i]->sock) != i_port ) - continue; - - /* Cannot re-use host if it uses TLS/SSL */ - if( httpd->host[i]->p_tls != NULL ) - continue; - -#ifdef AF_INET6 - if( httpd->host[i]->sock.ss_family == AF_INET6 ) - { - const struct sockaddr_in6 *p_hsock, *p_sock; - - p_hsock = (const struct sockaddr_in6 *)&httpd->host[i]->sock; - p_sock = (const struct sockaddr_in6 *)ptr->ai_addr; - - if( memcmp( &p_hsock->sin6_addr, &in6addr_any, - sizeof( struct in6_addr ) ) && - ( p_sock->sin6_family != AF_INET6 || - memcmp( &p_hsock->sin6_addr, &p_sock->sin6_addr, - sizeof( struct in6_addr ) ) ) ) - continue; /* does not match */ - } - else if( ptr->ai_family == PF_INET6 ) - continue; - else -#endif - if( httpd->host[i]->sock.ss_family == AF_INET ) - { - const struct sockaddr_in *p_hsock, *p_sock; - p_hsock = (const struct sockaddr_in *)&httpd->host[i]->sock; - p_sock = (const struct sockaddr_in *)ptr->ai_addr; - - if( p_hsock->sin_addr.s_addr != INADDR_ANY && - ( p_sock->sin_family != AF_INET || - p_hsock->sin_addr.s_addr != p_sock->sin_addr.s_addr ) ) - continue; /* does not match */ - } - else if( ptr->ai_family == PF_INET ) - continue; - else - { - msg_Dbg( p_this, "host with unknown address family" ); - continue; - } - - freeaddrinfo( res ); - - /* yep found */ - host = httpd->host[i]; - host->i_ref++; - - vlc_mutex_unlock( lockval.p_address ); + /* yep found */ + host->i_ref++; - msg_Dbg( p_this, "host already registered" ); - return host; - } + vlc_mutex_unlock( lockval.p_address ); + return host; + } - /* create the listening socket */ - fd = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ); - if( fd == -1 ) - continue; + host = NULL; - /* reuse socket */ + /* determine TLS configuration */ + if ( psz_cert != NULL ) + { + p_tls = tls_ServerCreate( p_this, psz_cert, psz_key ); + if ( p_tls == NULL ) { - int dummy = 1; - if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, - (void *)&dummy, sizeof( dummy ) ) < 0 ) - { - msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR)" ); - } + msg_Err( p_this, "TLS initialization error" ); + goto error; } - /* bind it */ - if( bind( fd, ptr->ai_addr, ptr->ai_addrlen ) ) - { - msg_Err( p_this, "cannot bind socket" ); - goto socket_error; - } - /* set to non-blocking */ -#if defined( WIN32 ) || defined( UNDER_CE ) - { - unsigned long i_dummy = 1; - if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 ) - { - msg_Err( p_this, "cannot set socket to non-blocking mode" ); - goto socket_error; - } - } -#else + if ( ( psz_ca != NULL) && tls_ServerAddCA( p_tls, psz_ca ) ) { - unsigned int i_flags; - if( ( i_flags = fcntl( fd, F_GETFL, 0 ) ) < 0 ) - { - msg_Err( p_this, "cannot F_GETFL socket" ); - goto socket_error; - } - if( fcntl( fd, F_SETFL, i_flags | O_NONBLOCK ) < 0 ) - { - msg_Err( p_this, "cannot F_SETFL O_NONBLOCK" ); - goto socket_error; - } + msg_Err( p_this, "TLS CA error" ); + goto error; } -#endif - /* listen */ - if( listen( fd, LISTEN_BACKLOG ) < 0 ) + + if ( ( psz_crl != NULL) && tls_ServerAddCRL( p_tls, psz_crl ) ) { - msg_Err( p_this, "cannot listen socket" ); - goto socket_error; + msg_Err( p_this, "TLS CRL error" ); + goto error; } - - break; // success - -socket_error: - net_Close( fd ); - fd = -1; - } - - - if( fd == -1 ) - { - freeaddrinfo( res ); - goto error; } + else + p_tls = NULL; /* create the new host */ host = vlc_object_create( p_this, sizeof( httpd_host_t ) ); host->httpd = httpd; vlc_mutex_init( httpd, &host->lock ); host->i_ref = 1; - host->fd = fd; - memcpy( &host->sock, ptr->ai_addr, ptr->ai_addrlen ); - host->i_sock_size = ptr->ai_addrlen; + host->fd = net_ListenTCP( p_this, psz_host, i_port ); + if( host->fd == NULL ) + { + msg_Err( p_this, "cannot create socket(s) for HTTP host" ); + goto error; + } + + host->i_port = i_port; + host->psz_hostname = psz_host; + host->i_url = 0; host->url = NULL; host->i_client = 0; host->client = NULL; - freeaddrinfo( res ); host->p_tls = p_tls; /* create the thread */ @@ -1185,19 +1009,25 @@ socket_error: return host; error: + free( psz_host ); + if( httpd->i_host <= 0 ) + { + vlc_object_release( httpd ); + vlc_object_detach( httpd ); + vlc_object_destroy( httpd ); + } vlc_mutex_unlock( lockval.p_address ); - if( fd != -1 ) - net_Close( fd ); - if( host != NULL ) { + net_ListenClose( host->fd ); vlc_mutex_destroy( &host->lock ); vlc_object_destroy( host ); } - /* TODO destroy no more used httpd TODO */ - vlc_object_release( httpd ); + if( p_tls != NULL ) + tls_ServerDelete( p_tls ); + return NULL; } @@ -1213,8 +1043,6 @@ void httpd_HostDelete( httpd_host_t *host ) var_Get( httpd->p_libvlc, "httpd_mutex", &lockval ); vlc_mutex_lock( lockval.p_address ); - vlc_object_release( httpd ); - host->i_ref--; if( host->i_ref > 0 ) { @@ -1249,13 +1077,17 @@ void httpd_HostDelete( httpd_host_t *host ) if( host->p_tls != NULL) tls_ServerDelete( host->p_tls ); - net_Close( host->fd ); + + net_ListenClose( host->fd ); + free( host->psz_hostname ); + vlc_mutex_destroy( &host->lock ); vlc_object_destroy( host ); if( httpd->i_host <= 0 ) { msg_Info( httpd, "httpd doesn't reference any host, deleting" ); + vlc_object_release( httpd ); vlc_object_detach( httpd ); vlc_object_destroy( httpd ); } @@ -1265,6 +1097,7 @@ void httpd_HostDelete( httpd_host_t *host ) /* register a new url */ static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, char *psz_user, char *psz_password, + char **ppsz_hosts, int i_hosts, vlc_bool_t b_check ) { httpd_url_t *url; @@ -1292,6 +1125,12 @@ static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, url->psz_url = strdup( psz_url ); url->psz_user = strdup( psz_user ? psz_user : "" ); url->psz_password = strdup( psz_password ? psz_password : "" ); + url->i_hosts = 0; + url->ppsz_hosts = NULL; + for( i = 0; i < i_hosts; i++ ) + { + TAB_APPEND( url->i_hosts, url->ppsz_hosts, strdup(ppsz_hosts[i]) ); + } for( i = 0; i < HTTPD_MSG_MAX; i++ ) { url->catch[i].cb = NULL; @@ -1305,17 +1144,19 @@ static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, } httpd_url_t *httpd_UrlNew( httpd_host_t *host, char *psz_url, - char *psz_user, char *psz_password ) + char *psz_user, char *psz_password, + char **ppsz_hosts, int i_hosts ) { return httpd_UrlNewPrivate( host, psz_url, psz_user, - psz_password, VLC_FALSE ); + psz_password, ppsz_hosts, i_hosts, VLC_FALSE ); } httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, char *psz_url, - char *psz_user, char *psz_password ) + char *psz_user, char *psz_password, + char **ppsz_hosts, int i_hosts ) { return httpd_UrlNewPrivate( host, psz_url, psz_user, - psz_password, VLC_TRUE ); + psz_password, ppsz_hosts, i_hosts, VLC_TRUE ); } /* register callback on a url */ @@ -1344,6 +1185,10 @@ void httpd_UrlDelete( httpd_url_t *url ) free( url->psz_url ); free( url->psz_user ); free( url->psz_password ); + for( i = 0; i < url->i_hosts; i++ ) + { + TAB_REMOVE( url->i_hosts, url->ppsz_hosts, url->ppsz_hosts[0] ); + } for( i = 0; i < host->i_client; i++ ) { @@ -1488,50 +1333,27 @@ void httpd_ClientModeBidir( httpd_client_t *cl ) char* httpd_ClientIP( httpd_client_t *cl ) { -#ifdef HAVE_GETNAMEINFO - char sz_ip[INET6_ADDRSTRLEN + 2]; int i; + char sz_ip[NI_MAXNUMERICHOST + 2]; - if( (cl->sock.ss_family == AF_INET6) && - IN6_IS_ADDR_V4MAPPED( &((const struct sockaddr_in6 *) - &cl->sock)->sin6_addr) ) - { - /* If client is using IPv4 but server is using IPv6 */ - struct sockaddr_in a; - - memset( &a, 0, sizeof( a ) ); - a.sin_family = AF_INET; - a.sin_port = ((const struct sockaddr_in6 *)&cl->sock)->sin6_port; - a.sin_addr.s_addr = ((const uint32_t *)&((const struct sockaddr_in6 *) - &cl->sock)->sin6_addr)[3]; - i = getnameinfo( (const struct sockaddr *)&a, sizeof( a ), - &sz_ip[1], INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST ); - } - else - i = getnameinfo( (const struct sockaddr *)&cl->sock, cl->i_sock_size, - &sz_ip[1], INET6_ADDRSTRLEN, NULL, 0, - NI_NUMERICHOST ); + i = vlc_getnameinfo( (const struct sockaddr *)&cl->sock, cl->i_sock_size, + sz_ip+1, NI_MAXNUMERICHOST, NULL, NI_NUMERICHOST ); if( i != 0 ) - /* FIXME: msg_Err */ return NULL; - - if( strchr( &sz_ip[1], ':' ) != NULL ) + + /* semi-colon in address => must add bracket for HTTP */ + if( strchr( sz_ip + 1, ':' ) != NULL ) { - *sz_ip = '['; + sz_ip[0] = '['; i = strlen( sz_ip ); sz_ip[i++] = ']'; sz_ip[i] = '\0'; - - return strdup( sz_ip ); + + return strdup(sz_ip); } - return strdup( &sz_ip[1] ); - -#else - /* FIXME not thread safe */ - return strdup( inet_ntoa( ((const struct sockaddr_in *)&cl->sock)->sin_addr ) ); -#endif + return strdup(sz_ip + 1); } static void httpd_ClientClean( httpd_client_t *cl ) @@ -1539,7 +1361,7 @@ static void httpd_ClientClean( httpd_client_t *cl ) if( cl->fd >= 0 ) { if( cl->p_tls != NULL ) - tls_SessionClose( cl->p_tls ); + tls_ServerSessionClose( cl->p_tls ); net_Close( cl->fd ); cl->fd = -1; } @@ -1612,7 +1434,7 @@ static void httpd_ClientRecv( httpd_client_t *cl ) if( cl->i_buffer >= 4 ) { - fprintf( stderr, "peek=%4.4s\n", cl->p_buffer ); + /*fprintf( stderr, "peek=%4.4s\n", cl->p_buffer );*/ /* detect type */ if( cl->p_buffer[0] == '$' ) { @@ -1726,7 +1548,7 @@ static void httpd_ClientRecv( httpd_client_t *cl ) p = NULL; cl->query.i_type = HTTPD_MSG_NONE; - fprintf( stderr, "received new request=%s\n", cl->p_buffer); + /*fprintf( stderr, "received new request=%s\n", cl->p_buffer);*/ for( i = 0; msg_type[i].name != NULL; i++ ) { @@ -1898,7 +1720,7 @@ static void httpd_ClientRecv( httpd_client_t *cl ) cl->i_activity_timeout = 0; /* Debugging only */ - if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE ) + /*if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE ) { int i; @@ -1921,7 +1743,7 @@ static void httpd_ClientRecv( httpd_client_t *cl ) fprintf( stderr, " - option name='%s' value='%s'\n", cl->query.name[i], cl->query.value[i] ); } - } + }*/ } @@ -1966,8 +1788,8 @@ static void httpd_ClientSend( httpd_client_t *cl ) cl->i_buffer = 0; cl->i_buffer_size = (uint8_t*)p - cl->p_buffer; - fprintf( stderr, "sending answer\n" ); - fprintf( stderr, "%s", cl->p_buffer ); + /*fprintf( stderr, "sending answer\n" ); + fprintf( stderr, "%s", cl->p_buffer );*/ } i_len = httpd_NetSend( cl, &cl->p_buffer[cl->i_buffer], @@ -2071,6 +1893,8 @@ static void httpd_HostThread( httpd_host_t *host ) struct timeval timeout; fd_set fds_read; fd_set fds_write; + /* FIXME: (too) many int variables */ + int fd, i_fd; int i_handle_max = 0; int i_ret; int i_client; @@ -2087,8 +1911,14 @@ static void httpd_HostThread( httpd_host_t *host ) FD_ZERO( &fds_read ); FD_ZERO( &fds_write ); - FD_SET( host->fd, &fds_read ); - i_handle_max = host->fd; + i_handle_max = -1; + + for( i_fd = 0; (fd = host->fd[i_fd]) != -1; i_fd++ ) + { + FD_SET( fd, &fds_read ); + if( fd > i_handle_max ) + i_handle_max = fd; + } /* prepare a new TLS session */ if( ( p_tls == NULL ) && ( host->p_tls != NULL ) ) @@ -2105,14 +1935,6 @@ static void httpd_HostThread( httpd_host_t *host ) ( cl->i_activity_timeout > 0 && cl->i_activity_date+cl->i_activity_timeout < mdate()) ) ) ) { - char *ip; - - // FIXME: it sucks to allocate memory on the stack for debug - ip = httpd_ClientIP( cl ); - msg_Dbg( host, "connection closed(%s)", - (ip != NULL) ? ip : "unknown" ); - free( ip ); - httpd_ClientClean( cl ); TAB_REMOVE( host->i_client, host->client, cl ); free( cl ); @@ -2237,6 +2059,7 @@ static void httpd_HostThread( httpd_host_t *host ) else { vlc_bool_t b_auth_failed = VLC_FALSE; + vlc_bool_t b_hosts_failed = VLC_FALSE; int i; /* Search the url and trigger callbacks */ @@ -2248,6 +2071,23 @@ static void httpd_HostThread( httpd_host_t *host ) { if( url->catch[i_msg].cb ) { + if( answer && url->i_hosts ) + { + char *ip = httpd_ClientIP( cl ); + if( ip != NULL ) + { + if( net_CheckIP( host, ip, + url->ppsz_hosts, + url->i_hosts ) <= 0 ) + { + b_hosts_failed = VLC_TRUE; + free( ip ); + break; + } + free( ip ); + } + } + if( answer && ( *url->psz_user || *url->psz_password ) ) { /* create the headers */ @@ -2306,7 +2146,23 @@ static void httpd_HostThread( httpd_host_t *host ) answer->i_version= 0; p = answer->p_body = malloc( 1000 + strlen(query->psz_url) ); - if( b_auth_failed ) + if( b_hosts_failed ) + { + answer->i_status = 403; + answer->psz_status = strdup( "Forbidden" ); + + p += sprintf( p, "\n" ); + p += sprintf( p, "\n" ); + p += sprintf( p, "Error 403\n" ); + p += sprintf( p, "\n" ); + p += sprintf( p, "\n" ); + p += sprintf( p, "

403 Forbidden (%s)

\n", query->psz_url ); + p += sprintf( p, "
\n" ); + p += sprintf( p, "VideoLAN\n" ); + p += sprintf( p, "\n" ); + p += sprintf( p, "\n" ); + } + else if( b_auth_failed ) { answer->i_status = 401; answer->psz_status = strdup( "Authorization Required" ); @@ -2447,7 +2303,11 @@ static void httpd_HostThread( httpd_host_t *host ) if( i_ret == -1 && errno != EINTR ) { - msg_Warn( host, "cannot select sockets" ); +#if defined(WIN32) || defined(UNDER_CE) + msg_Warn( host, "cannot select sockets (%d)", WSAGetLastError( ) ); +#else + msg_Warn( host, "cannot select sockets : %s", strerror( errno ) ); +#endif msleep( 1000 ); continue; } @@ -2457,71 +2317,66 @@ static void httpd_HostThread( httpd_host_t *host ) } /* accept new connections */ - if( FD_ISSET( host->fd, &fds_read ) ) + for( i_fd = 0; (fd = host->fd[i_fd]) != -1; i_fd++ ) { - int i_sock_size = sizeof( struct sockaddr_storage ); - struct sockaddr_storage sock; - int fd; - - fd = accept( host->fd, (struct sockaddr *)&sock, &i_sock_size ); - if( fd >= 0 ) + if( FD_ISSET( fd, &fds_read ) ) { - int i_state = 0; - - /* set this new socket non-block */ -#if defined( WIN32 ) || defined( UNDER_CE ) - { - unsigned long i_dummy = 1; - ioctlsocket( fd, FIONBIO, &i_dummy ); - } -#else - fcntl( fd, F_SETFL, O_NONBLOCK ); -#endif - - if( p_tls != NULL) + int i_sock_size = sizeof( struct sockaddr_storage ); + struct sockaddr_storage sock; + + fd = accept( fd, (struct sockaddr *)&sock, &i_sock_size ); + if( fd >= 0 ) { - switch ( tls_SessionHandshake( p_tls, fd ) ) + int i_state = 0; + + /* set this new socket non-block */ + #if defined( WIN32 ) || defined( UNDER_CE ) { - case -1: - msg_Err( host, "Rejecting TLS connection" ); - net_Close( fd ); - fd = -1; - p_tls = NULL; - break; - - case 1: /* missing input - most likely */ - i_state = HTTPD_CLIENT_TLS_HS_IN; - break; - - case 2: /* missing output */ - i_state = HTTPD_CLIENT_TLS_HS_OUT; - break; + unsigned long i_dummy = 1; + ioctlsocket( fd, FIONBIO, &i_dummy ); + } + #else + fcntl( fd, F_SETFL, O_NONBLOCK ); + #endif + + if( p_tls != NULL) + { + switch ( tls_ServerSessionHandshake( p_tls, fd ) ) + { + case -1: + msg_Err( host, "Rejecting TLS connection" ); + net_Close( fd ); + fd = -1; + p_tls = NULL; + break; + + case 1: /* missing input - most likely */ + i_state = HTTPD_CLIENT_TLS_HS_IN; + break; + + case 2: /* missing output */ + i_state = HTTPD_CLIENT_TLS_HS_OUT; + break; + } + } + + if( fd >= 0 ) + { + httpd_client_t *cl; + + cl = httpd_ClientNew( fd, &sock, i_sock_size, p_tls ); + p_tls = NULL; + vlc_mutex_lock( &host->lock ); + TAB_APPEND( host->i_client, host->client, cl ); + vlc_mutex_unlock( &host->lock ); + + if( i_state != 0 ) + cl->i_state = i_state; // override state for TLS } - } - - if( fd >= 0 ) - { - char *ip; - httpd_client_t *cl; - - cl = httpd_ClientNew( fd, &sock, i_sock_size, p_tls ); - p_tls = NULL; - vlc_mutex_lock( &host->lock ); - TAB_APPEND( host->i_client, host->client, cl ); - vlc_mutex_unlock( &host->lock ); - - if( i_state != 0 ) - cl->i_state = i_state; // override state for TLS - - // FIXME: it sucks to allocate memory for debug - ip = httpd_ClientIP( cl ); - msg_Dbg( host, "new connection (%s)", - ip != NULL ? ip : "unknown" ); - if( ip != NULL) - free( ip ); } } } + /* now try all others socket */ vlc_mutex_lock( &host->lock ); for( i_client = 0; i_client < host->i_client; i_client++ ) @@ -2553,71 +2408,9 @@ static void httpd_HostThread( httpd_host_t *host ) } vlc_mutex_unlock( &host->lock ); } -} -#ifndef HAVE_GETADDRINFO -static int BuildAddr( struct sockaddr_in * p_socket, - const char * psz_address, int i_port ) -{ - /* Reset struct */ - memset( p_socket, 0, sizeof( struct sockaddr_in ) ); - p_socket->sin_family = AF_INET; /* family */ - p_socket->sin_port = htons( (uint16_t)i_port ); - if( !*psz_address ) - { - p_socket->sin_addr.s_addr = INADDR_ANY; - } - else - { - struct hostent * p_hostent; - - /* Try to convert address directly from in_addr - this will work if - * psz_address is dotted decimal. */ -#ifdef HAVE_ARPA_INET_H - if( !inet_aton( psz_address, &p_socket->sin_addr ) ) -#else - p_socket->sin_addr.s_addr = inet_addr( psz_address ); - -/* if( p_socket->sin_addr.s_addr == INADDR_NONE )*/ - if( p_socket->sin_addr.s_addr == INADDR_BROADCAST ) -#endif - { - /* We have a fqdn, try to find its address */ - if ( (p_hostent = gethostbyname( psz_address )) == NULL ) - { - return( -1 ); - } - - /* Copy the first address of the host in the socket address */ - memcpy( &((struct sockaddr_in *)p_socket)->sin_addr, p_hostent->h_addr_list[0], - p_hostent->h_length ); - } - } - return( 0 ); -} -#endif - -static int GetAddrPort( const struct sockaddr_storage *p_ss ) -{ - int i_port = 0; - - switch (p_ss->ss_family) - { -#ifdef AF_INET6 - case AF_INET6: - i_port = ((const struct sockaddr_in6 *)p_ss)->sin6_port; - break; -#endif - - case AF_INET: - i_port = ((const struct sockaddr_in *)p_ss)->sin_port; - break; - - default: - return -1; - } - - return ntohs( i_port ); + if( p_tls != NULL ) + tls_ServerSessionClose( p_tls ); } #else /* ENABLE_HTTPD */