summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2016-12-13 20:11:24 -0500
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2016-12-15 21:00:08 -0500
commit63cc41a45671dccadaa0723915fc1389327530cd (patch)
treec7c74e51aa77c732ad77042d3a245a554d0454a2
parent5d3be8ccba5fe48b09e2a4e816f21c39038adfd0 (diff)
downloadpython-systemd-63cc41a45671dccadaa0723915fc1389327530cd.tar.gz
daemon: add basic support for sd_is_socket_sockaddr
Later on a proper wrapper in daemon.py should be added.
-rw-r--r--setup.py3
-rw-r--r--systemd/_daemon.c55
-rw-r--r--systemd/util.c169
-rw-r--r--systemd/util.h33
4 files changed, 254 insertions, 6 deletions
diff --git a/setup.py b/setup.py
index 529f613..1acfbc5 100644
--- a/setup.py
+++ b/setup.py
@@ -61,7 +61,8 @@ _reader = Extension('systemd/_reader',
**lib('libsystemd', 'libsystemd-journal', **defines))
_daemon = Extension('systemd/_daemon',
sources = ['systemd/_daemon.c',
- 'systemd/pyutil.c'],
+ 'systemd/pyutil.c',
+ 'systemd/util.c'],
extra_compile_args=['-Werror=implicit-function-declaration'],
**lib('libsystemd', 'libsystemd-daemon', **defines))
id128 = Extension('systemd/id128',
diff --git a/systemd/_daemon.c b/systemd/_daemon.c
index 87a33f0..f122722 100644
--- a/systemd/_daemon.c
+++ b/systemd/_daemon.c
@@ -2,7 +2,7 @@
/***
- Copyright 2013 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
+ Copyright 2013-2016 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
python-systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -31,12 +31,18 @@
#include "systemd/sd-daemon.h"
#include "pyutil.h"
#include "macro.h"
+#include "util.h"
#if LIBSYSTEMD_VERSION >= 214
# define HAVE_PID_NOTIFY
-# if LIBSYSTEMD_VERSION >= 219
-# define HAVE_PID_NOTIFY_WITH_FDS
-# endif
+#endif
+
+#if LIBSYSTEMD_VERSION >= 219
+# define HAVE_PID_NOTIFY_WITH_FDS
+#endif
+
+#if LIBSYSTEMD_VERSION >= 233
+# define HAVE_IS_SOCKET_SOCKADDR
#endif
PyDoc_STRVAR(module__doc__,
@@ -311,6 +317,42 @@ static PyObject* is_socket_inet(PyObject *self, PyObject *args) {
return PyBool_FromLong(r);
}
+#ifdef HAVE_IS_SOCKET_SOCKADDR
+PyDoc_STRVAR(is_socket_sockaddr__doc__,
+ "_is_socket_sockaddr(fd, address, type=0, listening=-1) -> bool\n\n"
+ "Wraps sd_is_socket_inet_sockaddr(3).\n"
+ "`address` is a systemd-style numerical IPv4 or IPv6 address as used in\n"
+ "ListenStream=. A port may be included after a colon (\":\"). See\n"
+ "systemd.socket(5) for details.\n\n"
+ "Constants for `family` are defined in the socket module."
+);
+
+static PyObject* is_socket_sockaddr(PyObject *self, PyObject *args) {
+ int r;
+ int fd, type = 0, listening = -1;
+ const char *address;
+ union sockaddr_union addr = {};
+ unsigned addr_len;
+
+ if (!PyArg_ParseTuple(args, "is|ii:_is_socket_sockaddr",
+ &fd,
+ &address,
+ &type, &listening))
+ return NULL;
+
+ r = parse_sockaddr(address, &addr, &addr_len);
+ if (r < 0) {
+ set_error(r, NULL, "Cannot parse address");
+ return NULL;
+ }
+
+ r = sd_is_socket_sockaddr(fd, type, &addr.sa, addr_len, listening);
+ if (set_error(r, NULL, NULL) < 0)
+ return NULL;
+
+ return PyBool_FromLong(r);
+}
+#endif
PyDoc_STRVAR(is_socket_unix__doc__,
"_is_socket_unix(fd, type, listening, path) -> bool\n\n"
@@ -355,8 +397,11 @@ static PyMethodDef methods[] = {
{ "_is_mq", is_mq, METH_VARARGS, is_mq__doc__},
{ "_is_socket", is_socket, METH_VARARGS, is_socket__doc__},
{ "_is_socket_inet", is_socket_inet, METH_VARARGS, is_socket_inet__doc__},
+#ifdef HAVE_IS_SOCKET_SOCKADDR
+ { "_is_socket_sockaddr", is_socket_sockaddr, METH_VARARGS, is_socket_sockaddr__doc__},
+#endif
{ "_is_socket_unix", is_socket_unix, METH_VARARGS, is_socket_unix__doc__},
- { NULL, NULL, 0, NULL } /* Sentinel */
+ {} /* Sentinel */
};
#if PY_MAJOR_VERSION < 3
diff --git a/systemd/util.c b/systemd/util.c
new file mode 100644
index 0000000..c6ec3b2
--- /dev/null
+++ b/systemd/util.c
@@ -0,0 +1,169 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+/* stuff imported from systemd without any changes */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <net/if.h>
+
+#include "util.h"
+
+int safe_atou(const char *s, unsigned *ret_u) {
+ char *x = NULL;
+ unsigned long l;
+
+ assert(s);
+ assert(ret_u);
+
+ /* strtoul() is happy to parse negative values, and silently
+ * converts them to unsigned values without generating an
+ * error. We want a clean error, hence let's look for the "-"
+ * prefix on our own, and generate an error. But let's do so
+ * only after strtoul() validated that the string is clean
+ * otherwise, so that we return EINVAL preferably over
+ * ERANGE. */
+
+ errno = 0;
+ l = strtoul(s, &x, 0);
+ if (errno > 0)
+ return -errno;
+ if (!x || x == s || *x)
+ return -EINVAL;
+ if (s[0] == '-')
+ return -ERANGE;
+ if ((unsigned long) (unsigned) l != l)
+ return -ERANGE;
+
+ *ret_u = (unsigned) l;
+ return 0;
+}
+
+static bool socket_ipv6_is_supported(void) {
+ if (access("/proc/net/if_inet6", F_OK) != 0)
+ return false;
+
+ return true;
+}
+
+int parse_sockaddr(const char *s,
+ union sockaddr_union *addr, unsigned *addr_len) {
+
+ char *e, *n;
+ unsigned u;
+ int r;
+
+ if (*s == '[') {
+ /* IPv6 in [x:.....:z]:p notation */
+
+ e = strchr(s+1, ']');
+ if (!e)
+ return -EINVAL;
+
+ n = strndupa(s+1, e-s-1);
+
+ errno = 0;
+ if (inet_pton(AF_INET6, n, &addr->in6.sin6_addr) <= 0)
+ return errno > 0 ? -errno : -EINVAL;
+
+ e++;
+ if (*e != ':')
+ return -EINVAL;
+
+ e++;
+ r = safe_atou(e, &u);
+ if (r < 0)
+ return r;
+
+ if (u <= 0 || u > 0xFFFF)
+ return -EINVAL;
+
+ addr->in6.sin6_family = AF_INET6;
+ addr->in6.sin6_port = htobe16((uint16_t)u);
+ *addr_len = sizeof(struct sockaddr_in6);
+
+ } else {
+ e = strchr(s, ':');
+ if (e) {
+ r = safe_atou(e+1, &u);
+ if (r < 0)
+ return r;
+
+ if (u <= 0 || u > 0xFFFF)
+ return -EINVAL;
+
+ n = strndupa(s, e-s);
+
+ /* IPv4 in w.x.y.z:p notation? */
+ r = inet_pton(AF_INET, n, &addr->in.sin_addr);
+ if (r < 0)
+ return -errno;
+
+ if (r > 0) {
+ /* Gotcha, it's a traditional IPv4 address */
+ addr->in.sin_family = AF_INET;
+ addr->in.sin_port = htobe16((uint16_t)u);
+ *addr_len = sizeof(struct sockaddr_in);
+ } else {
+ unsigned idx;
+
+ if (strlen(n) > IF_NAMESIZE-1)
+ return -EINVAL;
+
+ /* Uh, our last resort, an interface name */
+ idx = if_nametoindex(n);
+ if (idx == 0)
+ return -EINVAL;
+
+ addr->in6.sin6_family = AF_INET6;
+ addr->in6.sin6_port = htobe16((uint16_t)u);
+ addr->in6.sin6_scope_id = idx;
+ addr->in6.sin6_addr = in6addr_any;
+ *addr_len = sizeof(struct sockaddr_in6);
+ }
+ } else {
+ /* Just a port */
+ r = safe_atou(s, &u);
+ if (r < 0)
+ return r;
+
+ if (u <= 0 || u > 0xFFFF)
+ return -EINVAL;
+
+ if (socket_ipv6_is_supported()) {
+ addr->in6.sin6_family = AF_INET6;
+ addr->in6.sin6_port = htobe16((uint16_t)u);
+ addr->in6.sin6_addr = in6addr_any;
+ *addr_len = sizeof(struct sockaddr_in6);
+ } else {
+ addr->in.sin_family = AF_INET;
+ addr->in.sin_port = htobe16((uint16_t)u);
+ addr->in.sin_addr.s_addr = INADDR_ANY;
+ *addr_len = sizeof(struct sockaddr_in);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/systemd/util.h b/systemd/util.h
new file mode 100644
index 0000000..337920c
--- /dev/null
+++ b/systemd/util.h
@@ -0,0 +1,33 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+union sockaddr_union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+ struct sockaddr_in6 in6;
+};
+
+int safe_atou(const char *s, unsigned *ret_u);
+int parse_sockaddr(const char *s,
+ union sockaddr_union *addr, unsigned *addr_len);