示例#1
0
/** \brief Stores detailed info of error occurred in the toolkit's functions
 *
 * \param in_function_name char * - the function name or place of error
 * \param fmt char* - printf() like
 * \return void
 *
 * \internal
 * Stores extended error info with AP_ERRNO_CUSTOM_MESSAGE error type. See ap_error/'*.h' for additional stuff
 * String generated by fmt will be truncated to ap_error_str_maxlen
 */
void ap_error_set_custom(const char *in_function_name, char *fmt, ...) /*  internal. stores some message if error occured in the toolkit's functions */
{
    va_list vl;


    va_start(vl, fmt);
    ap_error_set_detailed(in_function_name, AP_ERRNO_CUSTOM_MESSAGE, fmt, vl);
    va_end(vl);
}
/** \brief Do poll task for given socket descriptor. It's a simpler interface to epoll()
 *
 * \param fd int - open socket descriptor
 * \return int -1 if general error, 0 if no events, otherwise state bits AP_NET_POLLER_ST_*
 *
 * Doing the round-robin polling on registered socket descriptors.
 * So each call to this function returning status bit field for the next descriptor in list.
 * bits are:
 * AP_NET_POLLER_ST_ERROR - Error detected
 * AP_NET_POLLER_ST_IN - Data available from peer
 * AP_NET_POLLER_ST_OUT - Socket ready to send data
 */
int ap_net_poller_single_fd(int fd)
{
    int poll_status;
    int epoll_fd;
    struct epoll_event ev;


    epoll_fd = epoll_create(1);

    if (epoll_fd == -1)
    {
        ap_error_set(_func_name, AP_ERRNO_SYSTEM);
        return -1;
    }

    ev.events = EPOLLIN | EPOLLOUT;
    ev.data.fd = fd;

    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1)
    {
        ap_error_set_detailed(_func_name, AP_ERRNO_SYSTEM, "epoll_ctl() add listen_socket_fd");
        close(epoll_fd);

        return -1;
    }

    poll_status = epoll_wait(epoll_fd, &ev, 1, 0);

    if (poll_status == -1)
    {
        ap_error_set(_func_name, AP_ERRNO_SYSTEM);
        return -1;
    }

    close(epoll_fd);

    poll_status = 0;

    if ( ev.events & EPOLLIN ) /* incoming data available */
    	poll_status |= AP_NET_POLLER_ST_IN;

    if ( ev.events & EPOLLOUT ) /* can send */
    	poll_status |= AP_NET_POLLER_ST_OUT;

    if ( ev.events & (EPOLLERR | EPOLLHUP ) ) /* connection's ERROR */
    	poll_status |= AP_NET_POLLER_ST_ERROR;

    return poll_status;
}
/** \brief Creates and starts listener socket for incoming connections
 *
 * \param pool struct ap_net_conn_pool_t*
 * \param max_tries int - Re-try to bind() to a local address how many times
 * \param retry_sleep int - sleep time in second between re-trys
 * \return int - listener socket handle on OK or -1 on error
 *
 * max_tries and retry_sleep used to cyclically attempt to bind() to registered address.
 * This is usable if software is run on early system startup when interfaces can be uninitialized for a while.
 * For the TCP pool it also issues listen() system call.
 * Socket is set to non-blocking mode after bind() so listen() returns immediately.
 * Also poller is automatically created if not exists and re-created if found. Socket handle is registered in there automaticaly.
 */
int ap_net_conn_pool_listener_create(struct ap_net_conn_pool_t *pool, int max_tries, int retry_sleep)
{
	size_t addr_len;
	struct sockaddr *addr;


    ap_error_clear();

    if ( -1 != pool->listener.sock )
    {
        ap_error_set_custom(_func_name, "listener is already active");
        return -1;
    }

    pool->listener.sock = socket( bit_is_set(pool->flags, AP_NET_POOL_FLAGS_IPV6) ? AF_INET6 : AF_INET,
                                  bit_is_set(pool->flags, AP_NET_POOL_FLAGS_TCP) ? SOCK_STREAM : SOCK_DGRAM, 0 );

    if ( -1 == pool->listener.sock )
    {
        ap_error_set_detailed(_func_name, AP_ERRNO_SYSTEM, "socket()");
        return -1;
    }

    if (bit_is_set(pool->flags, AP_NET_POOL_FLAGS_IPV6))
    {
    	addr = (struct sockaddr *)(&pool->listener.addr6);
    	addr_len = sizeof(struct sockaddr_in6);
    }
    else
    {
    	addr = (struct sockaddr *)(&pool->listener.addr4);
    	addr_len = sizeof(struct sockaddr_in);
    }

    for(;;)
    {
        if ( -1 != bind( pool->listener.sock, addr, addr_len ) )
            break; /*  bind OK */

        if ( --max_tries == 0 )
        {
            ap_error_set_detailed(_func_name, AP_ERRNO_SYSTEM, "bind()");
            close(pool->listener.sock);
            pool->listener.sock = -1;
            return -1;
        }

        ap_log_do_syslog(LOG_ERR, "%s: %m: retries left: %d, sleeping for %d sec(s)", _func_name, max_tries, retry_sleep);

        sleep(retry_sleep);
    }

   	fcntl(pool->listener.sock, F_SETFL, fcntl(pool->listener.sock, F_GETFL) | O_NONBLOCK);

   	if ( pool->poller != NULL ) /* recreating. ugly, but fine for now */
   	{
   		ap_net_poller_destroy(pool->poller);
   		pool->poller = NULL;
   	}

	if ( ! ap_net_conn_pool_poller_create(pool))
	{
        close(pool->listener.sock);
        pool->listener.sock = -1;
        return -1;
	}

    if ( bit_is_set(pool->flags, AP_NET_POOL_FLAGS_TCP)
         && 0 != listen(pool->listener.sock, pool->max_connections) )
    {
        ap_error_set_detailed(_func_name, AP_ERRNO_SYSTEM, "listen()");
        close(pool->listener.sock);
        pool->listener.sock = -1;
        return -1;
    }

    return pool->listener.sock;
}