Now we hopefully won't need to touch it for a long time.
#include <stdlib.h>
-/** Append 'addr = {port = int, udp = bool, tcp = bool}' */
+/** Table and next index on top of stack -> append entries for given endpoint_array_t. */
static int net_list_add(const char *key, void *val, void *ext)
{
lua_State *L = (lua_State *)ext;
struct endpoint *ep = &ep_array->at[j];
lua_newtable(L); // connection tuple
- lua_pushstring(L, key);
- lua_setfield(L, -2, "ip");
+ if (ep->flags.kind) {
+ lua_pushstring(L, ep->flags.kind);
+ } else if (ep->flags.tls) {
+ lua_pushliteral(L, "tls");
+ } else {
+ lua_pushliteral(L, "dns");
+ }
+ lua_setfield(L, -2, "kind");
lua_newtable(L); // "transport" table
- switch (ep->flags.sock_type) {
- case SOCK_DGRAM:
- lua_pushliteral(L, "udp");
- lua_setfield(L, -2, "protocol");
- lua_pushinteger(L, ep->port);
- lua_setfield(L, -2, "port");
- lua_pushliteral(L, "none");
- lua_setfield(L, -2, "security");
+
+ switch (ep->family) {
+ case AF_INET:
+ lua_pushliteral(L, "inet4");
break;
- case SOCK_STREAM:
- lua_pushliteral(L, "tcp");
- lua_setfield(L, -2, "protocol");
- lua_pushinteger(L, ep->port);
- lua_setfield(L, -2, "port");
- if (ep->flags.tls) {
- lua_pushliteral(L, "tls");
- } else {
- lua_pushliteral(L, "none");
- }
- lua_setfield(L, -2, "security");
+ case AF_INET6:
+ lua_pushliteral(L, "inet6");
+ break;
+ case AF_UNIX:
+ lua_pushliteral(L, "unix");
break;
default:
+ lua_pushliteral(L, "invalid");
assert(!EINVAL);
- lua_pushliteral(L, "unknown");
- lua_setfield(L, -2, "protocol");
}
- lua_setfield(L, -2, "transport");
+ lua_setfield(L, -2, "family");
- lua_newtable(L); // "application" table
- if (ep->flags.kind) {
- lua_pushstring(L, ep->flags.kind);
+ lua_pushstring(L, key);
+ if (ep->family != AF_UNIX) {
+ lua_setfield(L, -2, "ip");
} else {
- lua_pushliteral(L, "dns");
+ lua_setfield(L, -2, "path");
+ }
+
+ if (ep->family != AF_UNIX) {
+ lua_pushinteger(L, ep->port);
+ lua_setfield(L, -2, "port");
+ }
+
+ if (ep->family == AF_UNIX) {
+ lua_pushliteral(L, "stream");
+ } else if (ep->flags.sock_type == SOCK_STREAM) {
+ lua_pushliteral(L, "tcp");
+ } else if (ep->flags.sock_type == SOCK_DGRAM) {
+ lua_pushliteral(L, "udp");
+ } else {
+ assert(!EINVAL);
+ lua_pushliteral(L, "invalid");
}
lua_setfield(L, -2, "protocol");
- lua_setfield(L, -2, "application");
+
+ lua_setfield(L, -2, "transport");
lua_settable(L, -3);
i++;
bool tls = (port == KR_DNS_TLS_PORT);
const char *kind = NULL;
- if (n > 2) {
+ if (n > 2 && !lua_isnil(L, 3)) {
if (!lua_istable(L, 3))
lua_error_p(L, "wrong type of third parameter (table expected)");
tls = table_get_flag(L, 3, "tls", tls);
.. code-block:: none
- [127.0.0.1] => {
- [port] => 53
- [tcp] => true
- [udp] => true
- }
+ [1] => {
+ [kind] => tls
+ [transport] => {
+ [family] => inet4
+ [ip] => 127.0.0.1
+ [port] => 853
+ [protocol] => tcp
+ }
+ }
+ [2] => {
+ [kind] => dns
+ [transport] => {
+ [family] => inet6
+ [ip] => ::1
+ [port] => 53
+ [protocol] => udp
+ }
+ }
+ [3] => {
+ [kind] => dns
+ [transport] => {
+ [family] => inet6
+ [ip] => ::1
+ [port] => 53
+ [protocol] => tcp
+ }
+ }
.. function:: net.interfaces()
struct endpoint {
void *handle;
int fd;
+ int family;
uint16_t port;
_Bool engaged;
endpoint_flags_t flags;
/** Notify the registered function about endpoint getting open.
* If log_port < 1, don't log it. */
static int endpoint_open_lua_cb(struct network *net, struct endpoint *ep,
- const char *log_addr, int log_port)
+ const char *log_addr)
{
const bool ok = ep->flags.kind && !ep->handle && !ep->engaged && ep->fd != -1;
if (!ok) {
if (!pp && net->missing_kind_is_error) {
kr_log_error("warning: network socket kind '%s' not handled when opening '%s",
ep->flags.kind, log_addr);
- if (log_port >= 0)
- kr_log_error("#%d", log_port);
+ if (ep->family != AF_UNIX)
+ kr_log_error("#%d", ep->port);
kr_log_error("'. Likely causes: typo or not loading 'http' module.\n");
/* No hard error, for now. LATER: perhaps differentiate between
* explicit net.listen() calls and "just unused" systemd sockets.
lua_rawgeti(L, LUA_REGISTRYINDEX, fun_id);
lua_pushboolean(L, true /* open */);
lua_pushpointer(L, ep);
- if (log_port < 0) {
+ if (ep->family == AF_UNIX) {
lua_pushstring(L, log_addr);
} else {
- lua_pushfstring(L, "%s#%d", log_addr, log_port);
+ lua_pushfstring(L, "%s#%d", log_addr, ep->port);
}
if (lua_pcall(L, 3, 0, 0)) {
kr_log_error("error opening %s: %s\n", log_addr, lua_tostring(L, -1));
struct endpoint *ep = &eps->at[i];
const bool match = !ep->engaged && ep->flags.kind;
if (!match) continue;
- int ret = endpoint_open_lua_cb(net, ep, key, ep->port);
+ int ret = endpoint_open_lua_cb(net, ep, key);
if (ret) return ret;
}
return 0;
/** Open endpoint protocols. ep->flags were pre-set. */
static int open_endpoint(struct network *net, struct endpoint *ep,
- const struct sockaddr *sa, int fd,
- const char *log_addr, uint16_t log_port)
+ const struct sockaddr *sa, const char *log_addr)
{
- if ((sa != NULL) == (fd != -1)) {
+ if ((sa != NULL) == (ep->fd != -1)) {
assert(!EINVAL);
return kr_error(EINVAL);
}
}
if (sa) {
- fd = io_bind(sa, ep->flags.sock_type);
- if (fd < 0) return fd;
+ ep->fd = io_bind(sa, ep->flags.sock_type);
+ if (ep->fd < 0) return ep->fd;
}
- ep->fd = fd;
if (ep->flags.kind) {
/* This EP isn't to be managed internally after binding. */
- return endpoint_open_lua_cb(net, ep, log_addr, log_port);
+ return endpoint_open_lua_cb(net, ep, log_addr);
} else {
ep->engaged = true;
/* .engaged seems not really meaningful with .kind == NULL, but... */
if (!ep->handle) {
return kr_error(ENOMEM);
}
- return io_listen_udp(net->loop, ep_handle, fd);
+ return io_listen_udp(net->loop, ep_handle, ep->fd);
} /* else */
if (ep->flags.sock_type == SOCK_STREAM) {
if (!ep->handle) {
return kr_error(ENOMEM);
}
- return io_listen_tcp(net->loop, ep_handle, fd, net->tcp_backlog, ep->flags.tls);
+ return io_listen_tcp(net->loop, ep_handle, ep->fd,
+ net->tcp_backlog, ep->flags.tls);
} /* else */
assert(!EINVAL);
return NULL;
}
-/** \note pass either sa != NULL xor fd != -1;
- * \note ownership of flags.* is taken on success. */
+/** \note pass either sa != NULL xor ep.fd != -1;
+ * \note ownership of ep.flags.* is taken on success. */
static int create_endpoint(struct network *net, const char *addr_str,
- uint16_t port, endpoint_flags_t flags,
- const struct sockaddr *sa, int fd)
+ struct endpoint *ep, const struct sockaddr *sa)
{
/* Bind interfaces */
- struct endpoint ep = {
- .handle = NULL,
- .port = port,
- .flags = flags,
- };
- int ret = open_endpoint(net, &ep, sa, fd, addr_str, port);
+ int ret = open_endpoint(net, ep, sa, addr_str);
if (ret == 0) {
- ret = insert_endpoint(net, addr_str, &ep);
+ ret = insert_endpoint(net, addr_str, ep);
}
- if (ret != 0 && ep.handle) {
- endpoint_close(net, &ep, false);
+ if (ret != 0 && ep->handle) {
+ endpoint_close(net, ep, false);
}
return ret;
}
if (ret != 0) {
return kr_error(errno);
}
- int port = 0;
+
+ struct endpoint ep = {
+ .flags = flags,
+ .family = ss.ss_family,
+ .fd = fd,
+ };
+ /* Extract address string and port. */
char addr_str[INET6_ADDRSTRLEN]; /* https://tools.ietf.org/html/rfc4291 */
if (ss.ss_family == AF_INET) {
uv_ip4_name((const struct sockaddr_in*)&ss, addr_str, sizeof(addr_str));
- port = ntohs(((struct sockaddr_in *)&ss)->sin_port);
+ ep.port = ntohs(((struct sockaddr_in *)&ss)->sin_port);
} else if (ss.ss_family == AF_INET6) {
uv_ip6_name((const struct sockaddr_in6*)&ss, addr_str, sizeof(addr_str));
- port = ntohs(((struct sockaddr_in6 *)&ss)->sin6_port);
+ ep.port = ntohs(((struct sockaddr_in6 *)&ss)->sin6_port);
} else {
return kr_error(EAFNOSUPPORT);
}
/* always create endpoint for supervisor supplied fd
* even if addr+port is not unique */
- return create_endpoint(net, addr_str, port, flags, NULL, fd);
+ return create_endpoint(net, addr_str, &ep, NULL);
}
int network_listen(struct network *net, const char *addr, uint16_t port,
if (ret != 0) {
return ret;
}
- return create_endpoint(net, addr, port, flags, &sa.ip, -1);
+ struct endpoint ep = {
+ .flags = flags,
+ .fd = -1,
+ .port = port,
+ .family = sa.ip.sa_family,
+ };
+ return create_endpoint(net, addr, &ep, &sa.ip);
}
int network_close(struct network *net, const char *addr, int port)
/** Ways to listen on a socket. */
typedef struct {
- int sock_type; /**< SOCK_DGRAM or SOCK_STREAM */
- bool tls; /**< only used together with .tcp; TODO: meaningful if kind != NULL? */
+ int sock_type; /**< SOCK_DGRAM or SOCK_STREAM */
+ bool tls; /**< only used together with .kind == NULL and .tcp */
const char *kind; /**< tag for other types than the three usual */
} endpoint_flags_t;
/** Wrapper for a single socket to listen on.
* There are two types: normal have handle, special have flags.kind (and never both).
+ *
+ * LATER: .family might be unexpected for IPv4-in-IPv6 addresses.
*/
struct endpoint {
- uv_handle_t *handle; /**< uv_udp_t or uv_tcp_t */
- int fd;
- uint16_t port;
- bool engaged; /**< to some module or internally */
+ uv_handle_t *handle; /**< uv_udp_t or uv_tcp_t; NULL in case flags.kind != NULL */
+ int fd; /**< POSIX file-descriptor; always used. */
+ int family; /**< AF_INET or AF_INET6 or (in future) AF_UNIX */
+ uint16_t port; /**< TCP/UDP port. Meaningless with AF_UNIX. */
+ bool engaged; /**< to some module or internally */
endpoint_flags_t flags;
};
/** Start listenting on an open file-descriptor.
* \note flags.sock_type isn't meaningful here.
- * \note ownership of flags.* is taken on success.
+ * \note ownership of flags.* is taken on success. TODO: non-success?
*/
int network_listen_fd(struct network *net, int fd, endpoint_flags_t flags);
assert(worker.stats() ~= nil)
assert(net.interfaces() ~= nil)
-- Self-checks on loaded stuff
-assert(net.list()[1].ip == '{{SELF_ADDR}}')
+assert(net.list()[1].transport.ip == '{{SELF_ADDR}}')
assert(#modules.list() > 0)
-- Self-check timers
ev = event.recurrent(1 * sec, function (ev) return 1 end)
assert(worker.stats() ~= nil)
assert(net.interfaces() ~= nil)
-- Self-checks on loaded stuff
-assert(net.list()[1].ip == '{{SELF_ADDR}}')
+assert(net.list()[1].transport.ip == '{{SELF_ADDR}}')
assert(#modules.list() > 0)
-- Self-check timers
ev = event.recurrent(1 * sec, function (ev) return 1 end)
assert(worker.stats() ~= nil)
assert(net.interfaces() ~= nil)
-- Self-checks on loaded stuff
-assert(net.list()[1].ip == '{{SELF_ADDR}}')
+assert(net.list()[1].transport.ip == '{{SELF_ADDR}}')
assert(#modules.list() > 0)
-- Self-check timers
ev = event.recurrent(1 * sec, function (ev) return 1 end)
assert(worker.stats() ~= nil)
assert(net.interfaces() ~= nil)
-- Self-checks on loaded stuff
-assert(net.list()[1].ip == '{{SELF_ADDR}}')
+assert(net.list()[1].transport.ip == '{{SELF_ADDR}}')
assert(#modules.list() > 0)
-- Self-check timers
ev = event.recurrent(1 * sec, function (ev) return 1 end)
assert(worker.stats() ~= nil)
assert(net.interfaces() ~= nil)
-- Self-checks on loaded stuff
-assert(net.list()[1].ip == '{{SELF_ADDR}}')
+assert(net.list()[1].transport.ip == '{{SELF_ADDR}}')
assert(#modules.list() > 0)
-- Self-check timers
ev = event.recurrent(1 * sec, function (ev) return 1 end)
assert(worker.stats() ~= nil)
assert(net.interfaces() ~= nil)
-- Self-checks on loaded stuff
-assert(net.list()[1].ip == '{{SELF_ADDR}}')
+assert(net.list()[1].transport.ip == '{{SELF_ADDR}}')
assert(#modules.list() > 0)
-- Self-check timers
ev = event.recurrent(1 * sec, function (ev) return 1 end)
assert(worker.stats() ~= nil)
assert(net.interfaces() ~= nil)
-- Self-checks on loaded stuff
-assert(net.list()[1].ip == '{{SELF_ADDR}}')
+assert(net.list()[1].transport.ip == '{{SELF_ADDR}}')
assert(#modules.list() > 0)
-- Self-check timers
ev = event.recurrent(1 * sec, function (ev) return 1 end)
assert(worker.stats() ~= nil)
assert(net.interfaces() ~= nil)
-- Self-checks on loaded stuff
-assert(net.list()[1].ip == '{{SELF_ADDR}}')
+assert(net.list()[1].transport.ip == '{{SELF_ADDR}}')
assert(#modules.list() > 0)
-- Self-check timers
ev = event.recurrent(1 * sec, function (ev) return 1 end)
assert(worker.stats() ~= nil)
assert(net.interfaces() ~= nil)
-- Self-checks on loaded stuff
-assert(net.list()[1].ip == '{{SELF_ADDR}}')
+assert(net.list()[1].transport.ip == '{{SELF_ADDR}}')
assert(#modules.list() > 0)
-- Self-check timers
ev = event.recurrent(1 * sec, function (ev) return 1 end)
assert(worker.stats() ~= nil)
assert(net.interfaces() ~= nil)
-- Self-checks on loaded stuff
-assert(net.list()[1].ip == '{{SELF_ADDR}}')
+assert(net.list()[1].transport.ip == '{{SELF_ADDR}}')
assert(#modules.list() > 0)
-- Self-check timers
ev = event.recurrent(1 * sec, function (ev) return 1 end)
-Subproject commit 6edfef4f65e846f3aef0cbf3b80e88f39658a1c9
+Subproject commit 947858cb649a4d477c93441ca96d894f0e545e4a