📄 httpd.c
字号:
*****************************************************************************/#define LISTEN_BACKLOG 100static void httpd_HostThread( httpd_host_t * );static int GetAddrPort( const struct sockaddr_storage *p_ss );#ifndef HAVE_GETADDRINFOstruct 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_addrinfostatic 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, int i_port ){ return httpd_TLSHostNew( p_this, psz_host, i_port, NULL );}httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, char *psz_host, int i_port, tls_server_t *p_tls ){ 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; int check; memset( &hints, 0, sizeof( hints ) ); /* 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; 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'; check = getaddrinfo( psz_host, psz_port, &hints, &res ); if( check != 0 ) {#ifdef HAVE_GAI_STRERROR msg_Err( p_this, "cannot resolve %s:%d : %s", psz_host, i_port, gai_strerror( check ) );#else msg_Err( p_this, "cannot resolve %s:%d", psz_host, i_port );#endif 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; if( BuildAddr( &sock, psz_host, i_port ) ) { msg_Err( p_this, "cannot build address for %s:%d", psz_host, i_port ); 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 ); vlc_mutex_lock( lockval.p_address ); if( !(httpd = vlc_object_find( p_this, VLC_OBJECT_HTTPD, FIND_ANYWHERE )) ) { msg_Info( p_this, "creating httpd" ); if( ( httpd = vlc_object_create( p_this, VLC_OBJECT_HTTPD ) ) == NULL ) { vlc_mutex_unlock( lockval.p_address ); freeaddrinfo( res ); return NULL; } httpd->i_host = 0; httpd->host = NULL; vlc_object_yield( httpd ); vlc_object_attach( httpd, p_this->p_vlc ); } for( ptr = res; (ptr != NULL) && (fd == -1); ptr = ptr->ai_next ) { int i; if( ((unsigned)ptr->ai_addrlen) > sizeof( struct sockaddr_storage ) ) { msg_Dbg( p_this, "socket address too big" ); 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 ); msg_Dbg( p_this, "host already registered" ); return host; } /* create the listening socket */ fd = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ); if( fd == -1 ) continue; /* reuse socket */ { int dummy = 1; if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&dummy, sizeof( dummy ) ) < 0 ) { msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR)" ); } } /* 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 { 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; } }#endif /* listen */ if( listen( fd, LISTEN_BACKLOG ) < 0 ) { msg_Err( p_this, "cannot listen socket" ); goto socket_error; } break; // successsocket_error: net_Close( fd ); fd = -1; } if( fd == -1 ) { freeaddrinfo( res ); goto error; } /* 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->i_url = 0; host->url = NULL; host->i_client = 0; host->client = NULL; freeaddrinfo( res ); host->p_tls = p_tls; /* create the thread */ if( vlc_thread_create( host, "httpd host thread", httpd_HostThread, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) ) { msg_Err( p_this, "cannot spawn http host thread" ); goto error; } /* now add it to httpd */ TAB_APPEND( httpd->i_host, httpd->host, host ); vlc_mutex_unlock( lockval.p_address ); return host;error: 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 ) { vlc_mutex_destroy( &host->lock ); vlc_object_destroy( host ); } return NULL;}/* delete a host */void httpd_HostDelete( httpd_host_t *host ){ httpd_t *httpd = host->httpd; vlc_value_t lockval; int i; msg_Dbg( host, "httpd_HostDelete" ); var_Get( httpd->p_libvlc, "httpd_mutex", &lockval ); vlc_mutex_lock( lockval.p_address ); host->i_ref--; if( host->i_ref > 0 ) { /* still used */ vlc_mutex_unlock( lockval.p_address ); msg_Dbg( host, "httpd_HostDelete: host still used" ); return; } TAB_REMOVE( httpd->i_host, httpd->host, host ); msg_Dbg( host, "httpd_HostDelete: host removed from http" ); host->b_die = 1; vlc_thread_join( host ); msg_Dbg( host, "httpd_HostDelete: host thread joined" ); for( i = 0; i < host->i_url; i++ ) { msg_Err( host, "url still registered:%s", host->url[i]->psz_url ); } for( i = 0; i < host->i_client; i++ ) { httpd_client_t *cl = host->client[i]; msg_Warn( host, "client still connected" ); httpd_ClientClean( cl ); TAB_REMOVE( host->i_client, host->client, cl ); free( cl ); i--; /* TODO */ } if( host->p_tls != NULL) tls_ServerDelete( host->p_tls ); net_Close( host->fd ); 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 ); } vlc_mutex_unlock( lockval.p_address );}/* register a new url */static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, char *psz_user, char *psz_password, vlc_bool_t b_check ){ httpd_url_t *url; int i; vlc_mutex_lock( &host->lock ); if( b_check ) { for( i = 0; i < host->i_url; i++ ) { if( !strcmp( psz_url, host->url[i]->psz_url ) ) { msg_Warn( host->httpd, "cannot add '%s' (url already defined)", psz_url ); vlc_mutex_unlock( &host->lock ); return NULL; } } } url = malloc( sizeof( httpd_url_t ) ); url->host = host; vlc_mutex_init( host->httpd, &url->lock ); url->psz_url = strdup( psz_url ); url->psz_user = strdup( psz_user ? psz_user : "" ); url->psz_password = strdup( psz_password ? psz_password : "" ); for( i = 0; i < HTTPD_MSG_MAX; i++ ) { url->catch[i].cb = NULL; url->catch[i].p_sys = NULL; } TAB_APPEND( host->i_url, host->url, url ); vlc_mutex_unlock( &host->lock ); return url;}httpd_url_t *httpd_UrlNew( httpd_host_t *host, char *psz_url, char *psz_user, char *psz_password ){ return httpd_UrlNewPrivate( host, psz_url, psz_user, psz_password, VLC_FALSE );}httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, char *psz_url, char *psz_user, char *psz_password ){ return httpd_UrlNewPrivate( host, psz_url, psz_user, psz_password, VLC_TRUE );}/* register callback on a url */int httpd_UrlCatch( httpd_url_t *url, int i_msg, httpd_callback_t cb, httpd_callback_sys_t *p_sys ){ vlc_mutex_lock( &url->lock ); url->catch[i_msg].cb = cb;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -