⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpd.c

📁 video linux conference
💻 C
📖 第 1 页 / 共 5 页
字号:
 *****************************************************************************/#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 + -