Initial commit
This commit is contained in:
commit
c17b7a2201
1 changed files with 170 additions and 0 deletions
170
mod_unix_socket.c
Normal file
170
mod_unix_socket.c
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "httpd.h"
|
||||||
|
#include "http_config.h"
|
||||||
|
#include "http_protocol.h"
|
||||||
|
#include "ap_config.h"
|
||||||
|
#include "ap_listen.h"
|
||||||
|
#include "apr_strings.h"
|
||||||
|
#include "http_log.h"
|
||||||
|
|
||||||
|
static ap_listen_rec *
|
||||||
|
alloc_unix_listener (process_rec * process, const char *path,
|
||||||
|
const char *proto)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sun = {
|
||||||
|
.sun_family = AF_UNIX,
|
||||||
|
};
|
||||||
|
apr_os_sock_info_t si;
|
||||||
|
ap_listen_rec *rec;
|
||||||
|
apr_status_t rv;
|
||||||
|
int one = 1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
apr_cpystrn (sun.sun_path, path, sizeof (sun.sun_path));
|
||||||
|
|
||||||
|
rec = apr_palloc (process->pool, sizeof (*rec));
|
||||||
|
rec->protocol = apr_pstrdup (process->pool, proto);
|
||||||
|
rec->accept_func = NULL;
|
||||||
|
rec->next = NULL;
|
||||||
|
rec->active = 1;
|
||||||
|
|
||||||
|
if (unlink (sun.sun_path))
|
||||||
|
{
|
||||||
|
ap_log_perror (APLOG_MARK, APLOG_CRIT, APR_EGENERAL, process->pool,
|
||||||
|
APLOGNO (10100) "unlink failed: %s", strerror (errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = socket (AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
ap_log_perror (APLOG_MARK, APLOG_CRIT, APR_EGENERAL, process->pool,
|
||||||
|
APLOGNO (10101) "socket failed: %s", strerror (errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt (fd, SOL_SOCKET, SO_REUSEPORT,
|
||||||
|
(void *) &one, sizeof (one)) < 0)
|
||||||
|
{
|
||||||
|
ap_log_perror (APLOG_MARK, APLOG_CRIT, APR_EGENERAL, process->pool,
|
||||||
|
APLOGNO (10102) "setsockopt failed: %s",
|
||||||
|
strerror (errno));
|
||||||
|
close (fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* apr_socket_bind() is not used because apr_sockaddr_t is not compatible
|
||||||
|
* with sockaddr_un
|
||||||
|
*/
|
||||||
|
if (bind (fd, (struct sockaddr *) &sun, sizeof (sun)))
|
||||||
|
{
|
||||||
|
ap_log_perror (APLOG_MARK, APLOG_CRIT, APR_EGENERAL, process->pool,
|
||||||
|
APLOGNO (10103) "bind failed: %s", strerror (errno));
|
||||||
|
close (fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME (ugly hack): configure fake socket information to allow
|
||||||
|
* ap_setup_listeners() to set the protocol of servers.
|
||||||
|
* I don't know if it interacts well with other parts of the codebase
|
||||||
|
* (I haven't even checked properly the whole server/listen.c file!)
|
||||||
|
*/
|
||||||
|
si.os_sock = &fd;
|
||||||
|
si.remote = NULL;
|
||||||
|
si.local = NULL;
|
||||||
|
si.family = APR_INET;
|
||||||
|
si.type = SOCK_STREAM;
|
||||||
|
si.protocol = APR_PROTO_TCP;
|
||||||
|
|
||||||
|
rv = apr_os_sock_make (&rec->sd, &si, process->pool);
|
||||||
|
if (rv != APR_SUCCESS)
|
||||||
|
{
|
||||||
|
ap_log_perror (APLOG_MARK, APLOG_CRIT, APR_EGENERAL, process->pool,
|
||||||
|
APLOGNO (10104) "apr_os_sock_make failed (%d)", fd);
|
||||||
|
close (fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = apr_socket_listen (rec->sd, 10);
|
||||||
|
if (rv != APR_SUCCESS)
|
||||||
|
{
|
||||||
|
ap_log_perror (APLOG_MARK, APLOG_CRIT, rv, process->pool,
|
||||||
|
APLOGNO (10105) "apr_socket_listen failed (%d)", fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = apr_socket_addr_get (&rec->bind_addr, APR_LOCAL, rec->sd);
|
||||||
|
if (rv != APR_SUCCESS)
|
||||||
|
{
|
||||||
|
ap_log_perror (APLOG_MARK, APLOG_CRIT, rv, process->pool,
|
||||||
|
APLOGNO (10106) "apr_socket_addr_get failed (%d)", fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: implement useful parts of make_sock (server/listen.c) */
|
||||||
|
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
set_listen_path (cmd_parms * cmd, void *cfg, const char *path,
|
||||||
|
const char *proto)
|
||||||
|
{
|
||||||
|
ap_listen_rec *last;
|
||||||
|
ap_listen_rec *new;
|
||||||
|
apr_status_t rv;
|
||||||
|
const char *err;
|
||||||
|
|
||||||
|
err = ap_check_cmd_context (cmd, GLOBAL_ONLY);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp (proto, "http") && strcmp (proto, "https"))
|
||||||
|
{
|
||||||
|
return "Proto must be either 'http' or 'https'";
|
||||||
|
}
|
||||||
|
|
||||||
|
new = alloc_unix_listener (cmd->server->process, path, proto);
|
||||||
|
if (!new)
|
||||||
|
{
|
||||||
|
return "Failed to listen on Unix socket";
|
||||||
|
}
|
||||||
|
|
||||||
|
last = ap_listeners;
|
||||||
|
|
||||||
|
while (last && last->next)
|
||||||
|
{
|
||||||
|
last = last->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!last)
|
||||||
|
{
|
||||||
|
ap_listeners = new;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last->next = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const command_rec directives[] = {
|
||||||
|
AP_INIT_TAKE2 ("ListenUnixPath", set_listen_path, NULL, RSRC_CONF,
|
||||||
|
"Listen to Unix socket"),
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module AP_MODULE_DECLARE_DATA unix_socket_module = {
|
||||||
|
STANDARD20_MODULE_STUFF,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
directives,
|
||||||
|
NULL,
|
||||||
|
};
|
Loading…
Reference in a new issue