/*
- * Copyright (C) 2015-2018 "IoT.bzh"
+ * Copyright (C) 2015-2019 "IoT.bzh"
* Author José Bollo <jose.bollo@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
#include "afb-fdev.h"
#include "afb-socket.h"
-#include "afb-systemd.h"
+
#include "fdev.h"
#include "verbose.h"
+/******************************************************************************/
#define BACKLOG 5
/******************************************************************************/
/** type systemd */
Type_Systemd,
+ /** type virtual socket of L4 */
+ Type_L4,
+
/** type Unix */
Type_Unix
};
.noreuseaddr = 1,
.nolisten = 1
},
+ {
+ .prefix = "l4vsock:",
+ .type = Type_L4
+ },
{
.prefix = "unix:",
.type = Type_Unix
*
* @return the file descriptor number of the socket or -1 in case of error
*/
-static int open_tcp(const char *spec, int server)
+static int open_tcp(const char *spec, int server, int reuseaddr)
{
int rc, fd;
const char *service, *host, *tail;
struct addrinfo hint, *rai, *iai;
/* scan the uri */
- tail = strchr(spec, '/');
+ tail = strchrnul(spec, '/');
service = strchr(spec, ':');
if (tail == NULL || service == NULL || tail < service) {
errno = EINVAL;
memset(&hint, 0, sizeof hint);
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_STREAM;
+ if (server) {
+ hint.ai_flags = AI_PASSIVE;
+ if (host[0] == 0 || (host[0] == '*' && host[1] == 0))
+ host = NULL;
+ }
rc = getaddrinfo(host, service, &hint, &rai);
if (rc != 0) {
errno = EINVAL;
fd = socket(iai->ai_family, iai->ai_socktype, iai->ai_protocol);
if (fd >= 0) {
if (server) {
+ if (reuseaddr) {
+ rc = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &rc, sizeof rc);
+ }
rc = bind(fd, iai->ai_addr, iai->ai_addrlen);
} else {
rc = connect(fd, iai->ai_addr, iai->ai_addrlen);
return -1;
}
+/******************************************************************************/
+#if WITH_SYSTEMD
+
+#include "systemd.h"
+
/**
* open a systemd socket for server
*
*/
static int open_systemd(const char *spec)
{
-#if defined(NO_SYSTEMD_ACTIVATION)
- errno = EAFNOSUPPORT;
- return -1;
-#else
- return afb_systemd_fds_for(spec);
+ return systemd_fds_for(spec);
+}
#endif
+
+/******************************************************************************/
+#if WITH_L4VSOCK
+
+struct sockaddr_l4
+{
+ unsigned short sl4_family;
+ unsigned short port;
+ char name[8];
+ char _pad[4];
+};
+
+enum address_families_l4
+{
+ AF_VIO_SOCK = 50, /* virtio-based sockets, must match the number in Linux */
+ PF_VIO_SOCK = AF_VIO_SOCK,
+};
+
+#define DEFAULT_L4VSOCK_PORT 7777
+
+/**
+ * open a L4 VSOCK socket for client or server
+ *
+ * @param spec the specification of the path (prefix with @ for abstract)
+ * @param server 0 for client, server otherwise
+ *
+ * @return the file descriptor number of the socket or -1 in case of error
+ */
+static int open_l4(const char *spec, int server)
+{
+ int fd, rc;
+ struct sockaddr_l4 addr;
+ const char *port, *slash;
+ unsigned short portnum;
+ size_t length;
+
+ /* scan the spec */
+ port = strchr(spec, ':');
+ slash = strchr(spec, '/');
+ if (port && slash && slash < port) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (port) {
+ rc = atoi(port + 1);
+ if (rc <= 0 && rc > UINT16_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+ portnum = (unsigned short)rc;
+ length = port - spec;
+ } else {
+ portnum = DEFAULT_L4VSOCK_PORT;
+ length = slash ? slash - spec : strlen(spec);
+ }
+
+ /* check the length */
+ if (length >= sizeof addr.name) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ /* create a socket */
+ fd = socket(PF_VIO_SOCK, SOCK_STREAM, 0);
+ if (fd < 0)
+ return fd;
+
+ /* prepare address */
+ memset(&addr, 0, sizeof addr);
+ addr.sl4_family = AF_VIO_SOCK;
+ addr.port = portnum;
+ memcpy(addr.name, spec, length);
+
+ if (server) {
+ rc = bind(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
+ } else {
+ rc = connect(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
+ }
+ if (rc < 0) {
+ close(fd);
+ return rc;
+ }
+ return fd;
}
+#endif
+
/******************************************************************************/
/**
*/
static int open_uri(const char *uri, int server)
{
- int fd, rc, offset;
+ int fd, offset;
struct entry *e;
const char *api;
fd = open_unix(uri, server);
break;
case Type_Inet:
- fd = open_tcp(uri, server);
+ fd = open_tcp(uri, server, !e->noreuseaddr);
break;
+#if WITH_SYSTEMD
case Type_Systemd:
if (server)
fd = open_systemd(uri);
fd = -1;
}
break;
+#endif
+#if WITH_L4VSOCK
+ case Type_L4:
+ fd = open_l4(uri, server);
+ break;
+#endif
default:
errno = EAFNOSUPPORT;
fd = -1;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
if (server) {
- if (!e->noreuseaddr) {
- rc = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &rc, sizeof rc);
- }
if (!e->nolisten)
listen(fd, BACKLOG);
}
{
int offset;
const char *api;
+ struct entry *entry;
- get_entry(uri, &offset);
+ entry = get_entry(uri, &offset);
uri += offset;
+ uri += (entry->type == Type_Unix && *uri == '@');
api = strstr(uri, as_api);
if (api)
api += sizeof as_api - 1;