+
+/******************************************************************************/
+#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;