/** \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; }