summaryrefslogtreecommitdiff
path: root/src/lib/apputils/net-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/apputils/net-server.c')
-rw-r--r--src/lib/apputils/net-server.c254
1 files changed, 105 insertions, 149 deletions
diff --git a/src/lib/apputils/net-server.c b/src/lib/apputils/net-server.c
index 29ec84a15b22..a40da927ef16 100644
--- a/src/lib/apputils/net-server.c
+++ b/src/lib/apputils/net-server.c
@@ -105,17 +105,6 @@ paddr(struct sockaddr *sa)
return buf;
}
-/* Return true if sa is an IPv4 or IPv6 wildcard address. */
-static int
-is_wildcard(struct sockaddr *sa)
-{
- if (sa->sa_family == AF_INET6)
- return IN6_IS_ADDR_UNSPECIFIED(&sa2sin6(sa)->sin6_addr);
- else if (sa->sa_family == AF_INET)
- return sa2sin(sa)->sin_addr.s_addr == INADDR_ANY;
- return 0;
-}
-
/* KDC data. */
enum conn_type {
@@ -142,8 +131,8 @@ struct connection {
struct sockaddr_storage addr_s;
socklen_t addrlen;
char addrbuf[56];
- krb5_fulladdr faddr;
- krb5_address kaddr;
+ krb5_address remote_addr_buf;
+ krb5_fulladdr remote_addr;
/* Incoming data (TCP) */
size_t bufsiz;
@@ -451,14 +440,6 @@ loop_add_rpc_service(int default_port, const char *addresses, u_long prognum,
#define SOCKET_ERRNO errno
#include "foreachaddr.h"
-struct socksetup {
- verto_ctx *ctx;
- void *handle;
- const char *prog;
- krb5_error_code retval;
- int listen_backlog;
-};
-
static void
free_connection(struct connection *conn)
{
@@ -533,7 +514,7 @@ free_socket(verto_ctx *ctx, verto_ev *ev)
static verto_ev *
make_event(verto_ctx *ctx, verto_ev_flag flags, verto_callback callback,
- int sock, struct connection *conn, int addevent)
+ int sock, struct connection *conn)
{
verto_ev *ev;
void *tmp;
@@ -544,45 +525,44 @@ make_event(verto_ctx *ctx, verto_ev_flag flags, verto_callback callback,
return NULL;
}
- if (addevent) {
- if (!ADD(events, ev, tmp)) {
- com_err(conn->prog, ENOMEM, _("cannot save event"));
- verto_del(ev);
- return NULL;
- }
+ if (!ADD(events, ev, tmp)) {
+ com_err(conn->prog, ENOMEM, _("cannot save event"));
+ verto_del(ev);
+ return NULL;
}
verto_set_private(ev, conn, free_socket);
return ev;
}
-static verto_ev *
-add_fd(struct socksetup *data, int sock, enum conn_type conntype,
- verto_ev_flag flags, verto_callback callback, int addevent)
+static krb5_error_code
+add_fd(int sock, enum conn_type conntype, verto_ev_flag flags, void *handle,
+ const char *prog, verto_ctx *ctx, verto_callback callback,
+ verto_ev **ev_out)
{
struct connection *newconn;
+ *ev_out = NULL;
+
#ifndef _WIN32
if (sock >= FD_SETSIZE) {
- data->retval = EMFILE; /* XXX */
- com_err(data->prog, 0,
- _("file descriptor number %d too high"), sock);
- return 0;
+ com_err(prog, 0, _("file descriptor number %d too high"), sock);
+ return EMFILE;
}
#endif
newconn = malloc(sizeof(*newconn));
if (newconn == NULL) {
- data->retval = ENOMEM;
- com_err(data->prog, ENOMEM,
+ com_err(prog, ENOMEM,
_("cannot allocate storage for connection info"));
- return 0;
+ return ENOMEM;
}
memset(newconn, 0, sizeof(*newconn));
- newconn->handle = data->handle;
- newconn->prog = data->prog;
+ newconn->handle = handle;
+ newconn->prog = prog;
newconn->type = conntype;
- return make_event(data->ctx, flags, callback, sock, newconn, addevent);
+ *ev_out = make_event(ctx, flags, callback, sock, newconn);
+ return 0;
}
static void process_packet(verto_ctx *ctx, verto_ev *ev);
@@ -592,77 +572,62 @@ static void process_tcp_connection_write(verto_ctx *ctx, verto_ev *ev);
static void accept_rpc_connection(verto_ctx *ctx, verto_ev *ev);
static void process_rpc_connection(verto_ctx *ctx, verto_ev *ev);
-static verto_ev *
-add_tcp_read_fd(struct socksetup *data, int sock)
-{
- return add_fd(data, sock, CONN_TCP,
- VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST,
- process_tcp_connection_read, 1);
-}
-
/*
* Create a socket and bind it to addr. Ensure the socket will work with
* select(). Set the socket cloexec, reuseaddr, and if applicable v6-only.
- * Does not call listen(). Returns -1 on failure after logging an error.
+ * Does not call listen(). On failure, log an error and return an error code.
*/
-static int
-create_server_socket(struct socksetup *data, struct sockaddr *addr, int type)
+static krb5_error_code
+create_server_socket(struct sockaddr *addr, int type, const char *prog,
+ int *fd_out)
{
- int sock;
+ int sock, e;
+
+ *fd_out = -1;
sock = socket(addr->sa_family, type, 0);
if (sock == -1) {
- data->retval = errno;
- com_err(data->prog, errno, _("Cannot create TCP server socket on %s"),
+ e = errno;
+ com_err(prog, e, _("Cannot create TCP server socket on %s"),
paddr(addr));
- return -1;
+ return e;
}
set_cloexec_fd(sock);
#ifndef _WIN32 /* Windows FD_SETSIZE is a count. */
if (sock >= FD_SETSIZE) {
close(sock);
- com_err(data->prog, 0, _("TCP socket fd number %d (for %s) too high"),
+ com_err(prog, 0, _("TCP socket fd number %d (for %s) too high"),
sock, paddr(addr));
- return -1;
+ return EMFILE;
}
#endif
- if (setreuseaddr(sock, 1) < 0) {
- com_err(data->prog, errno,
- _("Cannot enable SO_REUSEADDR on fd %d"), sock);
- }
+ if (setreuseaddr(sock, 1) < 0)
+ com_err(prog, errno, _("Cannot enable SO_REUSEADDR on fd %d"), sock);
if (addr->sa_family == AF_INET6) {
#ifdef IPV6_V6ONLY
- if (setv6only(sock, 1))
- com_err(data->prog, errno,
- _("setsockopt(%d,IPV6_V6ONLY,1) failed"), sock);
- else
- com_err(data->prog, 0, _("setsockopt(%d,IPV6_V6ONLY,1) worked"),
+ if (setv6only(sock, 1)) {
+ com_err(prog, errno, _("setsockopt(%d,IPV6_V6ONLY,1) failed"),
sock);
+ } else {
+ com_err(prog, 0, _("setsockopt(%d,IPV6_V6ONLY,1) worked"), sock);
+ }
#else
krb5_klog_syslog(LOG_INFO, _("no IPV6_V6ONLY socket option support"));
#endif /* IPV6_V6ONLY */
}
if (bind(sock, addr, sa_socklen(addr)) == -1) {
- data->retval = errno;
- com_err(data->prog, errno, _("Cannot bind server socket on %s"),
- paddr(addr));
+ e = errno;
+ com_err(prog, e, _("Cannot bind server socket on %s"), paddr(addr));
close(sock);
- return -1;
+ return e;
}
- return sock;
-}
-
-static verto_ev *
-add_rpc_data_fd(struct socksetup *data, int sock)
-{
- return add_fd(data, sock, CONN_RPC,
- VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST,
- process_rpc_connection, 1);
+ *fd_out = sock;
+ return 0;
}
static const int one = 1;
@@ -716,12 +681,13 @@ static const enum conn_type bind_conn_types[] =
* The conn_type of this socket.
*/
static krb5_error_code
-setup_socket(struct socksetup *data, struct bind_address *ba,
- struct sockaddr *sock_address, verto_callback vcb,
- enum conn_type ctype)
+setup_socket(struct bind_address *ba, struct sockaddr *sock_address,
+ void *handle, const char *prog, verto_ctx *ctx,
+ int tcp_listen_backlog, verto_callback vcb, enum conn_type ctype)
{
krb5_error_code ret;
struct connection *conn;
+ verto_ev_flag flags;
verto_ev *ev = NULL;
int sock = -1;
@@ -729,18 +695,16 @@ setup_socket(struct socksetup *data, struct bind_address *ba,
bind_type_names[ba->type], paddr(sock_address));
/* Create the socket. */
- sock = create_server_socket(data, sock_address, bind_socktypes[ba->type]);
- if (sock == -1) {
- ret = data->retval;
+ ret = create_server_socket(sock_address, bind_socktypes[ba->type], prog,
+ &sock);
+ if (ret)
goto cleanup;
- }
/* Listen for backlogged connections on TCP sockets. (For RPC sockets this
* will be done by svc_register().) */
- if (ba->type == TCP && listen(sock, data->listen_backlog) != 0) {
+ if (ba->type == TCP && listen(sock, tcp_listen_backlog) != 0) {
ret = errno;
- com_err(data->prog, errno,
- _("Cannot listen on %s server socket on %s"),
+ com_err(prog, errno, _("Cannot listen on %s server socket on %s"),
bind_type_names[ba->type], paddr(sock_address));
goto cleanup;
}
@@ -748,7 +712,7 @@ setup_socket(struct socksetup *data, struct bind_address *ba,
/* Set non-blocking I/O for UDP and TCP listener sockets. */
if (ba->type != RPC && setnbio(sock) != 0) {
ret = errno;
- com_err(data->prog, errno,
+ com_err(prog, errno,
_("cannot set listening %s socket on %s non-blocking"),
bind_type_names[ba->type], paddr(sock_address));
goto cleanup;
@@ -757,19 +721,18 @@ setup_socket(struct socksetup *data, struct bind_address *ba,
/* Turn off the linger option for TCP sockets. */
if (ba->type == TCP && setnolinger(sock) != 0) {
ret = errno;
- com_err(data->prog, errno,
- _("cannot set SO_LINGER on %s socket on %s"),
+ com_err(prog, errno, _("cannot set SO_LINGER on %s socket on %s"),
bind_type_names[ba->type], paddr(sock_address));
goto cleanup;
}
/* Try to turn on pktinfo for UDP wildcard sockets. */
- if (ba->type == UDP && is_wildcard(sock_address)) {
+ if (ba->type == UDP && sa_is_wildcard(sock_address)) {
krb5_klog_syslog(LOG_DEBUG, _("Setting pktinfo on socket %s"),
paddr(sock_address));
ret = set_pktinfo(sock, sock_address->sa_family);
if (ret) {
- com_err(data->prog, ret,
+ com_err(prog, ret,
_("Cannot request packet info for UDP socket address "
"%s port %d"), paddr(sock_address), ba->port);
krb5_klog_syslog(LOG_INFO, _("System does not support pktinfo yet "
@@ -780,13 +743,11 @@ setup_socket(struct socksetup *data, struct bind_address *ba,
}
/* Add the socket to the event loop. */
- ev = add_fd(data, sock, ctype,
- VERTO_EV_FLAG_IO_READ |
- VERTO_EV_FLAG_PERSIST |
- VERTO_EV_FLAG_REINITIABLE, vcb, 1);
- if (ev == NULL) {
+ flags = VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST |
+ VERTO_EV_FLAG_REINITIABLE;
+ ret = add_fd(sock, ctype, flags, handle, prog, ctx, vcb, &ev);
+ if (ret) {
krb5_klog_syslog(LOG_ERR, _("Error attempting to add verto event"));
- ret = data->retval;
goto cleanup;
}
@@ -829,13 +790,10 @@ cleanup:
* This function uses getaddrinfo to figure out all the addresses. This will
* automatically figure out which socket families that should be used on the
* host making it useful even for wildcard addresses.
- *
- * Arguments:
- * - data
- * A pointer to the socksetup data.
*/
static krb5_error_code
-setup_addresses(struct socksetup *data)
+setup_addresses(verto_ctx *ctx, void *handle, const char *prog,
+ int tcp_listen_backlog)
{
/* An bind_type enum map for the verto callback functions. */
static verto_callback *const verto_callbacks[] = {
@@ -896,8 +854,8 @@ setup_addresses(struct socksetup *data)
/* Set the real port number. */
sa_setport(ai->ai_addr, addr.port);
- ret = setup_socket(data, &addr, ai->ai_addr,
- verto_callbacks[addr.type],
+ ret = setup_socket(&addr, ai->ai_addr, handle, prog, ctx,
+ tcp_listen_backlog, verto_callbacks[addr.type],
bind_conn_types[addr.type]);
if (ret) {
krb5_klog_syslog(LOG_ERR,
@@ -929,9 +887,9 @@ krb5_error_code
loop_setup_network(verto_ctx *ctx, void *handle, const char *prog,
int tcp_listen_backlog)
{
- struct socksetup setup_data;
+ krb5_error_code ret;
verto_ev *ev;
- int i, ret;
+ int i;
/* Check to make sure that at least one address was added to the loop. */
if (bind_addresses.n == 0)
@@ -942,15 +900,9 @@ loop_setup_network(verto_ctx *ctx, void *handle, const char *prog,
verto_del(ev);
events.n = 0;
- setup_data.ctx = ctx;
- setup_data.handle = handle;
- setup_data.prog = prog;
- setup_data.retval = 0;
- setup_data.listen_backlog = tcp_listen_backlog;
-
krb5_klog_syslog(LOG_INFO, _("setting up network..."));
- ret = setup_addresses(&setup_data);
- if (ret != 0) {
+ ret = setup_addresses(ctx, handle, prog, tcp_listen_backlog);
+ if (ret) {
com_err(prog, ret, _("Error setting up network"));
exit(1);
}
@@ -999,8 +951,10 @@ struct udp_dispatch_state {
void *handle;
const char *prog;
int port_fd;
- krb5_address addr;
- krb5_fulladdr faddr;
+ krb5_address remote_addr_buf;
+ krb5_fulladdr remote_addr;
+ krb5_address local_addr_buf;
+ krb5_fulladdr local_addr;
socklen_t saddr_len;
socklen_t daddr_len;
struct sockaddr_storage saddr;
@@ -1132,10 +1086,15 @@ process_packet(verto_ctx *ctx, verto_ev *ev)
state->request.length = cc;
state->request.data = state->pktbuf;
- state->faddr.address = &state->addr;
- init_addr(&state->faddr, ss2sa(&state->saddr));
+
+ state->remote_addr.address = &state->remote_addr_buf;
+ init_addr(&state->remote_addr, ss2sa(&state->saddr));
+
+ state->local_addr.address = &state->local_addr_buf;
+ init_addr(&state->local_addr, ss2sa(&state->daddr));
+
/* This address is in net order. */
- dispatch(state->handle, ss2sa(&state->daddr), &state->faddr,
+ dispatch(state->handle, &state->local_addr, &state->remote_addr,
&state->request, 0, ctx, process_packet_response, state);
}
@@ -1186,9 +1145,9 @@ accept_tcp_connection(verto_ctx *ctx, verto_ev *ev)
struct sockaddr_storage addr_s;
struct sockaddr *addr = (struct sockaddr *)&addr_s;
socklen_t addrlen = sizeof(addr_s);
- struct socksetup sockdata;
struct connection *newconn, *conn;
char tmpbuf[10];
+ verto_ev_flag flags;
verto_ev *newev;
conn = verto_get_private(ev);
@@ -1204,13 +1163,9 @@ accept_tcp_connection(verto_ctx *ctx, verto_ev *ev)
#endif
setnbio(s), setnolinger(s), setkeepalive(s);
- sockdata.ctx = ctx;
- sockdata.handle = conn->handle;
- sockdata.prog = conn->prog;
- sockdata.retval = 0;
-
- newev = add_tcp_read_fd(&sockdata, s);
- if (newev == NULL) {
+ flags = VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST;
+ if (add_fd(s, CONN_TCP, flags, conn->handle, conn->prog, ctx,
+ process_tcp_connection_read, &newev) != 0) {
close(s);
return;
}
@@ -1253,14 +1208,16 @@ accept_tcp_connection(verto_ctx *ctx, verto_ev *ev)
return;
}
newconn->offset = 0;
- newconn->faddr.address = &newconn->kaddr;
- init_addr(&newconn->faddr, ss2sa(&newconn->addr_s));
+ newconn->remote_addr.address = &newconn->remote_addr_buf;
+ init_addr(&newconn->remote_addr, ss2sa(&newconn->addr_s));
SG_SET(&newconn->sgbuf[0], newconn->lenbuf, 4);
SG_SET(&newconn->sgbuf[1], 0, 0);
}
struct tcp_dispatch_state {
struct sockaddr_storage local_saddr;
+ krb5_address local_addr_buf;
+ krb5_fulladdr local_addr;
struct connection *conn;
krb5_data request;
verto_ctx *ctx;
@@ -1288,7 +1245,7 @@ process_tcp_response(void *arg, krb5_error_code code, krb5_data *response)
state->conn->sgnum = 2;
ev = make_event(state->ctx, VERTO_EV_FLAG_IO_WRITE | VERTO_EV_FLAG_PERSIST,
- process_tcp_connection_write, state->sock, state->conn, 1);
+ process_tcp_connection_write, state->sock, state->conn);
if (ev) {
free(state);
return;
@@ -1381,7 +1338,6 @@ process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev)
} else {
/* msglen known. */
socklen_t local_saddrlen = sizeof(struct sockaddr_storage);
- struct sockaddr *local_saddrp = NULL;
len = conn->msglen - (conn->offset - 4);
nread = SOCKET_READ(verto_get_fd(ev),
@@ -1403,10 +1359,14 @@ process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev)
state->request.data = conn->buffer + 4;
if (getsockname(verto_get_fd(ev), ss2sa(&state->local_saddr),
- &local_saddrlen) == 0)
- local_saddrp = ss2sa(&state->local_saddr);
-
- dispatch(state->conn->handle, local_saddrp, &conn->faddr,
+ &local_saddrlen) < 0) {
+ krb5_klog_syslog(LOG_ERR, _("getsockname failed: %s"),
+ error_message(errno));
+ goto kill_tcp_connection;
+ }
+ state->local_addr.address = &state->local_addr_buf;
+ init_addr(&state->local_addr, ss2sa(&state->local_saddr));
+ dispatch(state->conn->handle, &state->local_addr, &conn->remote_addr,
&state->request, 1, ctx, process_tcp_response, state);
}
@@ -1489,18 +1449,13 @@ have_event_for_fd(int fd)
static void
accept_rpc_connection(verto_ctx *ctx, verto_ev *ev)
{
- struct socksetup sockdata;
+ verto_ev_flag flags;
struct connection *conn;
fd_set fds;
register int s;
conn = verto_get_private(ev);
- sockdata.ctx = ctx;
- sockdata.handle = conn->handle;
- sockdata.prog = conn->prog;
- sockdata.retval = 0;
-
/* Service the woken RPC listener descriptor. */
FD_ZERO(&fds);
FD_SET(verto_get_fd(ev), &fds);
@@ -1519,8 +1474,9 @@ accept_rpc_connection(verto_ctx *ctx, verto_ev *ev)
if (!FD_ISSET(s, &svc_fdset) || have_event_for_fd(s))
continue;
- newev = add_rpc_data_fd(&sockdata, s);
- if (newev == NULL)
+ flags = VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST;
+ if (add_fd(s, CONN_RPC, flags, conn->handle, conn->prog, ctx,
+ process_rpc_connection, &newev) != 0)
continue;
newconn = verto_get_private(newev);
@@ -1559,8 +1515,8 @@ accept_rpc_connection(verto_ctx *ctx, verto_ev *ev)
if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections)
kill_lru_tcp_or_rpc_connection(newconn->handle, newev);
- newconn->faddr.address = &newconn->kaddr;
- init_addr(&newconn->faddr, ss2sa(&newconn->addr_s));
+ newconn->remote_addr.address = &newconn->remote_addr_buf;
+ init_addr(&newconn->remote_addr, ss2sa(&newconn->addr_s));
}
}