*
*/
+#include "apr_network_io.h"
#include "httpd.h"
#include "http_config.h"
#include "ap_listen.h"
static int send_buffer_size;
/* TODO: make_sock is just begging and screaming for APR abstraction */
-static int make_sock(const struct sockaddr_in *server)
+static ap_status_t make_sock(ap_context_t *p, ap_listen_rec *server)
{
- int s;
+ ap_socket_t *s = server->sd;
int one = 1;
char addr[512];
+ ap_status_t stat;
- if (server->sin_addr.s_addr != htonl(INADDR_ANY))
- ap_snprintf(addr, sizeof(addr), "address %s port %d",
- inet_ntoa(server->sin_addr), ntohs(server->sin_port));
- else
- ap_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
+ ap_cpystrn(addr, "[@main/listen.c:make_sock(): inet_ntoa(server->sin_addr)]", sizeof addr);
- if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
- ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
- "make_sock: failed to get a socket for %s", addr);
- return -1;
- }
-
-#ifdef SO_REUSEADDR
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) {
- ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+ stat = ap_setsocketopt(s, APR_SO_REUSEADDR, one);
+ if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
"make_sock: for %s, setsockopt: (SO_REUSEADDR)", addr);
- close(s);
- return -1;
+ ap_close_socket(s);
+ return stat;
}
-#endif
- one = 1;
-#ifdef SO_KEEPALIVE
- if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(int)) < 0) {
- ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+
+ stat = ap_setsocketopt(s, APR_SO_KEEPALIVE, one);
+ if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
"make_sock: for %s, setsockopt: (SO_KEEPALIVE)", addr);
- close(s);
- return -1;
+ ap_close_socket(s);
+ return stat;
}
-#endif
/*
* To send data over high bandwidth-delay connections at full
*
* If no size is specified, use the kernel default.
*/
-#ifndef SO_SNDBUF
if (send_buffer_size) {
- if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
- (char *) &send_buffer_size, sizeof(int)) < 0) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, NULL,
+ stat = ap_setsocketopt(s, APR_SO_SNDBUF, send_buffer_size);
+ if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, stat, NULL,
"make_sock: failed to set SendBufferSize for %s, "
"using default", addr);
/* not a fatal error */
}
}
-#endif
- if (bind(s, (struct sockaddr *) server, sizeof(struct sockaddr_in)) == -1) {
- ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+ if ((stat = ap_bind(s)) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
"make_sock: could not bind to %s", addr);
- close(s);
- return -1;
+ ap_close_socket(s);
+ return stat;
}
- if (listen(s, ap_listenbacklog) == -1) {
- ap_log_error(APLOG_MARK, APLOG_ERR, NULL,
+ if ((stat = ap_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, stat, NULL,
"make_sock: unable to listen for connections on %s", addr);
- close(s);
- return -1;
+ ap_close_socket(s);
+ return stat;
}
- return s;
+ server->sd = s;
+ server->active = 1;
+ return APR_SUCCESS;
}
-static void close_listeners_on_exec(void *v)
+static ap_status_t close_listeners_on_exec(void *v)
{
ap_listen_rec *lr;
for (lr = ap_listeners; lr; lr = lr->next) {
- close(lr->fd);
+ ap_close_socket(lr->sd);
+ lr->active = 0;
}
+ return APR_SUCCESS;
}
-static void alloc_listener(struct sockaddr_in *local_addr)
+static void alloc_listener(process_rec *process, char *addr, unsigned int port)
{
ap_listen_rec **walk;
ap_listen_rec *new;
+ ap_status_t status;
+ char *oldaddr;
+ unsigned int oldport;
/* see if we've got an old listener for this address:port */
for (walk = &old_listeners; *walk; walk = &(*walk)->next) {
- if (!memcmp(&(*walk)->local_addr, local_addr, sizeof(local_addr))) {
+ ap_get_local_port(&oldport, (*walk)->sd);
+ ap_get_local_ipaddr(&oldaddr,(*walk)->sd);
+ if (!strcmp(oldaddr, addr) && port == oldport) {
/* re-use existing record */
new = *walk;
*walk = new->next;
}
/* this has to survive restarts */
- new = malloc(sizeof(ap_listen_rec));
- new->local_addr = *local_addr;
- new->fd = -1;
+ /* XXX - We need to deal with freeing this structure properly. */
+ new = ap_palloc(process->pool, sizeof(ap_listen_rec));
+ new->active = 0;
+ if ((status = ap_create_tcp_socket(&new->sd, NULL)) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, status, NULL,
+ "make_sock: failed to get a socket for %s", addr);
+ return;
+ }
+ ap_set_local_port(new->sd, port);
+ ap_set_local_ipaddr(new->sd, addr);
new->next = ap_listeners;
ap_listeners = new;
}
-int ap_listen_open(pool *pconf, unsigned port)
+int ap_listen_open(process_rec *process, unsigned port)
{
+ ap_context_t *pconf = process->pconf;
ap_listen_rec *lr;
ap_listen_rec *next;
int num_open;
- struct sockaddr_in local_addr;
/* allocate a default listener if necessary */
if (ap_listeners == NULL) {
- local_addr.sin_family = AF_INET;
- local_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* XXX */
- local_addr.sin_port = htons(port ? port : DEFAULT_HTTP_PORT);
- alloc_listener(&local_addr);
+ alloc_listener(process, APR_ANYADDR, port ? port : DEFAULT_HTTP_PORT);
}
num_open = 0;
for (lr = ap_listeners; lr; lr = lr->next) {
- if (lr->fd < 0) {
- lr->fd = make_sock(&lr->local_addr);
- }
- if (lr->fd >= 0) {
+ if (lr->active) {
++num_open;
}
+ else {
+ if (make_sock(pconf, lr) == APR_SUCCESS) {
+ ++num_open;
+ lr->active = 1;
+ }
+ }
}
/* close the old listeners */
for (lr = old_listeners; lr; lr = next) {
- close(lr->fd);
+ ap_close_socket(lr->sd);
+ lr->active = 0;
next = lr->next;
- free(lr);
+/* free(lr);*/
}
old_listeners = NULL;
{
char *ports;
unsigned short port;
- struct sockaddr_in local_addr;
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
ports = ips;
}
- local_addr.sin_family = AF_INET;
- if (ports == ips) { /* no address */
- local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- }
- else {
- local_addr.sin_addr.s_addr = ap_get_virthost_addr(ips, NULL);
- }
port = atoi(ports);
if (!port) {
return "Port must be numeric";
}
- local_addr.sin_port = htons(port);
- alloc_listener(&local_addr);
+ if (ports == ips) { /* no address */
+ alloc_listener(cmd->server->process, APR_ANYADDR, port);
+ }
+ else {
+ ips[(ports - ips) - 1] = '\0';
+ alloc_listener(cmd->server->process, ips, port);
+ }
return NULL;
}