rework socket handling

This commit is contained in:
Lennart Poettering 2010-01-23 03:35:54 +01:00
parent 5cb5a6ffc3
commit 542563babd
9 changed files with 223 additions and 100 deletions

View File

@ -132,21 +132,57 @@ static int config_parse_listen(
void *userdata) {
int r;
SocketPort *p;
Socket *s;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
if ((r = address_parse(data, rvalue)) < 0) {
log_error("[%s:%u] Failed to parse address value: %s", filename, line, rvalue);
return r;
s = (Socket*) data;
if (!(p = new0(SocketPort, 1)))
return -ENOMEM;
if (streq(lvalue, "ListenFIFO")) {
p->type = SOCKET_FIFO;
if (!(p->path = strdup(rvalue))) {
free(p);
return -ENOMEM;
}
} else {
p->type = SOCKET_SOCKET;
if ((r = socket_address_parse(&p->address, rvalue)) < 0) {
log_error("[%s:%u] Failed to parse address value: %s", filename, line, rvalue);
free(p);
return r;
}
if (streq(lvalue, "ListenStream"))
p->address.type = SOCK_STREAM;
else if (streq(lvalue, "ListenDatagram"))
p->address.type = SOCK_DGRAM;
else {
assert(streq(lvalue, "ListenSequentialPacket"));
p->address.type = SOCK_SEQPACKET;
}
if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
free(p);
return -EPROTONOSUPPORT;
}
}
p->fd = -1;
LIST_PREPEND(SocketPort, s->ports, p);
return 0;
}
static int config_parse_type(
static int config_parse_bind(
const char *filename,
unsigned line,
const char *section,
@ -155,22 +191,23 @@ static int config_parse_type(
void *data,
void *userdata) {
int *type = data;
int r;
Socket *s;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
if (streq(rvalue, "stream"))
*type = SOCK_STREAM;
else if (streq(rvalue, "dgram"))
*type = SOCK_DGRAM;
else {
log_error("[%s:%u] Failed to parse socket type value: %s", filename, line, rvalue);
return -EINVAL;
s = (Socket*) data;
if ((r = parse_boolean(rvalue)) < 0) {
log_error("[%s:%u] Failed to parse bind IPv6 only value: %s", filename, line, rvalue);
return r;
}
s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
return 0;
}
@ -188,18 +225,22 @@ int name_load_fragment(Name *n) {
};
const ConfigItem items[] = {
{ "Names", config_parse_names, &n->meta.names, "Meta" },
{ "Description", config_parse_string, &n->meta.description, "Meta" },
{ "Requires", config_parse_deps, n->meta.dependencies+NAME_REQUIRES, "Meta" },
{ "SoftRequires", config_parse_deps, n->meta.dependencies+NAME_SOFT_REQUIRES, "Meta" },
{ "Wants", config_parse_deps, n->meta.dependencies+NAME_WANTS, "Meta" },
{ "Requisite", config_parse_deps, n->meta.dependencies+NAME_REQUISITE, "Meta" },
{ "SoftRequisite", config_parse_deps, n->meta.dependencies+NAME_SOFT_REQUISITE, "Meta" },
{ "Conflicts", config_parse_deps, n->meta.dependencies+NAME_CONFLICTS, "Meta" },
{ "Before", config_parse_deps, n->meta.dependencies+NAME_BEFORE, "Meta" },
{ "After", config_parse_deps, n->meta.dependencies+NAME_AFTER, "Meta" },
{ "Listen", config_parse_listen, &n->socket.address, "Socket" },
{ "Type", config_parse_type, &n->socket.address.type, "Socket" },
{ "Names", config_parse_names, &n->meta.names, "Meta" },
{ "Description", config_parse_string, &n->meta.description, "Meta" },
{ "Requires", config_parse_deps, n->meta.dependencies+NAME_REQUIRES, "Meta" },
{ "SoftRequires", config_parse_deps, n->meta.dependencies+NAME_SOFT_REQUIRES, "Meta" },
{ "Wants", config_parse_deps, n->meta.dependencies+NAME_WANTS, "Meta" },
{ "Requisite", config_parse_deps, n->meta.dependencies+NAME_REQUISITE, "Meta" },
{ "SoftRequisite", config_parse_deps, n->meta.dependencies+NAME_SOFT_REQUISITE, "Meta" },
{ "Conflicts", config_parse_deps, n->meta.dependencies+NAME_CONFLICTS, "Meta" },
{ "Before", config_parse_deps, n->meta.dependencies+NAME_BEFORE, "Meta" },
{ "After", config_parse_deps, n->meta.dependencies+NAME_AFTER, "Meta" },
{ "ListenStream", config_parse_listen, &n->socket, "Socket" },
{ "ListenDatagram", config_parse_listen, &n->socket, "Socket" },
{ "ListenSequentialPacket", config_parse_listen, &n->socket, "Socket" },
{ "ListenFIFO", config_parse_listen, &n->socket, "Socket" },
{ "BindIPv6Only", config_parse_bind, &n->socket, "Socket" },
{ "Backlog", config_parse_unsigned, &n->socket.backlog, "Socket" },
{ NULL, NULL, NULL, NULL }
};

View File

@ -699,28 +699,28 @@ static int transaction_add_job_and_dependencies(Manager *m, JobType type, Name *
/* Finally, recursively add in all dependencies. */
if (type == JOB_START || type == JOB_RELOAD_OR_START) {
SET_FOREACH(dep, ret->name->meta.dependencies[NAME_REQUIRES], state)
if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, force, NULL)) != -EBADR)
if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
goto fail;
SET_FOREACH(dep, ret->name->meta.dependencies[NAME_SOFT_REQUIRES], state)
if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !force, force, NULL)) != -EBADR)
if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !force, force, NULL)) < 0 && r != -EBADR)
goto fail;
SET_FOREACH(dep, ret->name->meta.dependencies[NAME_WANTS], state)
if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, force, NULL)) != -EBADR)
if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, force, NULL)) < 0 && r != -EBADR)
goto fail;
SET_FOREACH(dep, ret->name->meta.dependencies[NAME_REQUISITE], state)
if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, force, NULL)) != -EBADR)
if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
goto fail;
SET_FOREACH(dep, ret->name->meta.dependencies[NAME_SOFT_REQUISITE], state)
if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !force, force, NULL)) != -EBADR)
if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !force, force, NULL)) < 0 && r != -EBADR)
goto fail;
SET_FOREACH(dep, ret->name->meta.dependencies[NAME_CONFLICTS], state)
if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, force, NULL)) != -EBADR)
if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
goto fail;
} else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
SET_FOREACH(dep, ret->name->meta.dependencies[NAME_REQUIRED_BY], state)
if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, force, NULL)) != -EBADR)
if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
goto fail;
}

1
name.c
View File

@ -367,6 +367,7 @@ void name_dump(Name *n, FILE *f, const char *prefix) {
[NAME_SOFT_REQUISITE] = "SoftRequisite",
[NAME_REQUIRED_BY] = "RequiredBy",
[NAME_SOFT_REQUIRED_BY] = "SoftRequiredBy",
[NAME_WANTED_BY] = "WantedBy",
[NAME_CONFLICTS] = "Conflicts",
[NAME_BEFORE] = "Before",
[NAME_AFTER] = "After",

View File

@ -7,12 +7,13 @@
#include <stdlib.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <net/if.h>
#include "macro.h"
#include "util.h"
#include "socket-util.h"
int address_parse(Address *a, const char *s) {
int socket_address_parse(SocketAddress *a, const char *s) {
int r;
char *e, *n;
unsigned u;
@ -21,6 +22,7 @@ int address_parse(Address *a, const char *s) {
assert(s);
memset(a, 0, sizeof(*a));
a->type = SOCK_STREAM;
if (*s == '[') {
/* IPv6 in [x:.....:z]:p notation */
@ -53,7 +55,6 @@ int address_parse(Address *a, const char *s) {
a->sockaddr.in6.sin6_family = AF_INET6;
a->sockaddr.in6.sin6_port = htons((uint16_t) u);
a->size = sizeof(struct sockaddr_in6);
a->bind_ipv6_only = true;
} else if (*s == '/') {
/* AF_UNIX socket */
@ -83,29 +84,46 @@ int address_parse(Address *a, const char *s) {
} else {
if ((e = strchr(s, ':'))) {
int r;
/* IPv4 in w.x.y.z:p notation */
if (!(n = strndup(s, e-s)))
return -ENOMEM;
errno = 0;
if (inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr) <= 0) {
free(n);
return errno != 0 ? -errno : -EINVAL;
}
free(n);
e++;
if ((r = safe_atou(e, &u)) < 0)
if ((r = safe_atou(e+1, &u)) < 0)
return r;
if (u <= 0 || u > 0xFFFF)
return -EINVAL;
a->sockaddr.in4.sin_family = AF_INET;
a->sockaddr.in4.sin_port = htons((uint16_t) u);
a->size = sizeof(struct sockaddr_in);
if (!(n = strndup(s, e-s)))
return -ENOMEM;
/* IPv4 in w.x.y.z:p notation? */
if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
free(n);
return -errno;
}
if (r > 0) {
/* Gotcha, it's a traditional IPv4 address */
free(n);
a->sockaddr.in4.sin_family = AF_INET;
a->sockaddr.in4.sin_port = htons((uint16_t) u);
a->size = sizeof(struct sockaddr_in);
} else {
unsigned idx;
/* Uh, our last resort, an interface name */
idx = if_nametoindex(n);
free(n);
if (n == 0)
return -EINVAL;
a->sockaddr.in6.sin6_family = AF_INET6;
a->sockaddr.in6.sin6_port = htons((uint16_t) u);
a->sockaddr.in6.sin6_scope_id = idx;
memcpy(&a->sockaddr.in6.sin6_addr, &in6addr_any, INET6_ADDRSTRLEN);
a->size = sizeof(struct sockaddr_in6);
}
} else {
/* Just a port */
@ -116,8 +134,8 @@ int address_parse(Address *a, const char *s) {
return -EINVAL;
a->sockaddr.in6.sin6_family = AF_INET6;
memcpy(&a->sockaddr.in6.sin6_addr, &in6addr_any, INET6_ADDRSTRLEN);
a->sockaddr.in6.sin6_port = htons((uint16_t) u);
memcpy(&a->sockaddr.in6.sin6_addr, &in6addr_any, INET6_ADDRSTRLEN);
a->size = sizeof(struct sockaddr_in6);
}
}
@ -125,10 +143,10 @@ int address_parse(Address *a, const char *s) {
return 0;
}
int address_verify(const Address *a) {
int socket_address_verify(const SocketAddress *a) {
assert(a);
switch (address_family(a)) {
switch (socket_address_family(a)) {
case AF_INET:
if (a->size != sizeof(struct sockaddr_in))
return -EINVAL;
@ -176,15 +194,15 @@ int address_verify(const Address *a) {
}
}
int address_print(const Address *a, char **p) {
int socket_address_print(const SocketAddress *a, char **p) {
int r;
assert(a);
assert(p);
if ((r = address_verify(a)) < 0)
if ((r = socket_address_verify(a)) < 0)
return r;
switch (address_family(a)) {
switch (socket_address_family(a)) {
case AF_INET: {
char *ret;
@ -256,16 +274,25 @@ int address_print(const Address *a, char **p) {
}
}
int address_listen(const Address *a, int backlog) {
int socket_address_listen(const SocketAddress *a, int backlog, SocketAddressBindIPv6Only only) {
int r, fd;
assert(a);
if ((r = address_verify(a)) < 0)
if ((r = socket_address_verify(a)) < 0)
return r;
if ((fd = socket(address_family(a), a->type, 0)) < 0)
if ((fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)) < 0)
return -errno;
if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0) {
close_nointr(fd);
return -errno;
}
}
if (bind(fd, &a->sockaddr.sa, a->size) < 0) {
close_nointr(fd);
return -errno;
@ -277,14 +304,5 @@ int address_listen(const Address *a, int backlog) {
return -errno;
}
if (address_family(a) == AF_INET6) {
int flag = a->bind_ipv6_only;
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0) {
close_nointr(fd);
return -errno;
}
}
return 0;
}

View File

@ -10,7 +10,7 @@
#include "macro.h"
#include "util.h"
typedef struct Address {
typedef struct SocketAddress {
union {
struct sockaddr sa;
struct sockaddr_in in4;
@ -25,16 +25,19 @@ typedef struct Address {
/* Socket type, i.e. SOCK_STREAM, SOCK_DGRAM, ... */
int type;
} SocketAddress;
/* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
bool bind_ipv6_only;
} Address;
typedef enum SocketAddressBindIPv6Only {
SOCKET_ADDRESS_DEFAULT,
SOCKET_ADDRESS_BOTH,
SOCKET_ADDRESS_IPV6_ONLY
} SocketAddressBindIPv6Only;
#define address_family(a) ((a)->sockaddr.sa.sa_family)
#define socket_address_family(a) ((a)->sockaddr.sa.sa_family)
int address_parse(Address *a, const char *s);
int address_print(const Address *a, char **p);
int address_verify(const Address *a);
int address_listen(const Address *a, int backlog);
int socket_address_parse(SocketAddress *a, const char *s);
int socket_address_print(const SocketAddress *a, char **p);
int socket_address_verify(const SocketAddress *a);
int socket_address_listen(const SocketAddress *a, int backlog, SocketAddressBindIPv6Only only);
#endif

View File

@ -7,10 +7,24 @@ static int socket_load(Name *n) {
Socket *s = SOCKET(n);
exec_context_defaults(&s->exec_context);
s->backlog = SOMAXCONN;
return name_load_fragment_and_dropin(n);
}
static const char* listen_lookup(int type) {
if (type == SOCK_STREAM)
return "ListenStream";
else if (type == SOCK_DGRAM)
return "ListenDatagram";
else if (type == SOCK_SEQPACKET)
return "ListenSequentialPacket";
assert_not_reached("Unkown socket type");
return NULL;
}
static void socket_dump(Name *n, FILE *f, const char *prefix) {
static const char* const state_table[_SOCKET_STATE_MAX] = {
@ -33,24 +47,35 @@ static void socket_dump(Name *n, FILE *f, const char *prefix) {
SocketExecCommand c;
Socket *s = SOCKET(n);
const char *t;
int r;
char *k;
SocketPort *p;
assert(s);
if ((r = address_print(&n->socket.address, &k)) < 0)
t = strerror(-r);
else
t = k;
fprintf(f,
"%sSocket State: %s\n"
"%sAddress: %s\n",
"%sBindIPv6Only: %s\n"
"%sBacklog: %u\n",
prefix, state_table[s->state],
prefix, t);
prefix, yes_no(s->bind_ipv6_only),
prefix, s->backlog);
free(k);
LIST_FOREACH(p, s->ports) {
if (p->type == SOCKET_SOCKET) {
const char *t;
int r;
char *k;
if ((r = socket_address_print(&p->address, &k)) < 0)
t = strerror(-r);
else
t = k;
fprintf(f, "%s%s: %s\n", prefix, listen_lookup(p->address.type), k);
free(k);
} else
fprintf(f, "%sListenFIFO: %s\n", prefix, p->path);
}
exec_context_dump(&s->exec_context, f, prefix);
@ -62,6 +87,14 @@ static void socket_dump(Name *n, FILE *f, const char *prefix) {
}
}
static int socket_start(Name *n) {
return 0;
}
static int socket_stop(Name *n) {
return 0;
}
static NameActiveState socket_active_state(Name *n) {
static const NameActiveState table[_SOCKET_STATE_MAX] = {
@ -79,14 +112,20 @@ static NameActiveState socket_active_state(Name *n) {
}
static void socket_free_hook(Name *n) {
unsigned i;
SocketExecCommand c;
Socket *s = SOCKET(n);
SocketPort *p;
assert(s);
for (i = 0; i < s->n_fds; i++)
close_nointr(s->fds[i]);
while ((p = s->ports)) {
LIST_REMOVE(SocketPort, s->ports, p);
if (p->fd >= 0)
close_nointr(p->fd);
free(p->path);
free(p);
}
exec_context_free(&s->exec_context);
@ -103,8 +142,8 @@ const NameVTable socket_vtable = {
.load = socket_load,
.dump = socket_dump,
.start = NULL,
.stop = NULL,
.start = socket_start,
.stop = socket_stop,
.reload = NULL,
.active_state = socket_active_state,

View File

@ -6,6 +6,7 @@
typedef struct Socket Socket;
#include "name.h"
#include "socket-util.h"
typedef enum SocketState {
SOCKET_DEAD,
@ -27,14 +28,34 @@ typedef enum SocketExecCommand {
_SOCKET_EXEC_MAX
} SocketExecCommand;
typedef enum SocketType {
SOCKET_SOCKET,
SOCKET_FIFO
} SocketType;
typedef struct SocketPort SocketPort;
struct SocketPort {
SocketType type;
SocketAddress address;
char *path;
int fd;
LIST_FIELDS(SocketPort);
};
struct Socket {
Meta meta;
SocketState state;
Address address;
int *fds;
unsigned n_fds;
LIST_HEAD(SocketPort, ports);
/* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
bool bind_ipv6_only;
unsigned backlog;
ExecCommand* exec_command[_SOCKET_EXEC_MAX];
ExecContext exec_context;

View File

@ -2,5 +2,5 @@
Description=Postfix SMTP Socket
[Socket]
Listen=25
Type=stream
ListenStream=25
ListenFIFO=/dev/test

View File

@ -2,5 +2,5 @@
Description=Syslog Socket
[Socket]
Listen=/dev/log
Type=dgram
ListenDatagram=/dev/log
ListenStream=eth0:4711