All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ramon Ribeiro <rhpr@cesar.org.br>
To: ell@lists.01.org
Subject: [PATCH v1 1/2] dbus: Add support to tcp address
Date: Mon, 15 Apr 2019 09:23:26 -0300	[thread overview]
Message-ID: <1555331007-26977-2-git-send-email-rhpr@cesar.org.br> (raw)
In-Reply-To: <1555331007-26977-1-git-send-email-rhpr@cesar.org.br>

[-- Attachment #1: Type: text/plain, Size: 6120 bytes --]

This patch allows a dbus client to connect to a dbus-daemon server
address listenning a TCP transport protocol.
A non-blocking TCP socket is created to avoid blocking the main event
loop.
---
 ell/dbus.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 146 insertions(+), 5 deletions(-)

diff --git a/ell/dbus.c b/ell/dbus.c
index 3a84c90..3a495d0 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -31,8 +31,11 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
+#include <netdb.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <sys/select.h>
+#include <netinet/in.h>
 #include <errno.h>
 
 #include "util.h"
@@ -75,6 +78,7 @@ struct l_dbus_ops {
 struct l_dbus {
 	struct l_io *io;
 	char *guid;
+	char *transport;
 	bool negotiate_unix_fd;
 	bool support_unix_fd;
 	bool is_ready;
@@ -466,7 +470,8 @@ static bool auth_read_handler(struct l_io *io, void *user_data)
 				return false;
 
 			break;
-		}
+		} else if (len == 0)
+			close(fd);
 
 		offset += len;
 	}
@@ -511,7 +516,10 @@ static bool auth_read_handler(struct l_io *io, void *user_data)
 		} else if (!strncmp(ptr, "REJECTED ", 9)) {
 			static const char *command = "AUTH ANONYMOUS\r\n";
 
-			dbus->negotiate_unix_fd = true;
+			if (!strcmp(dbus->transport, "unix"))
+				dbus->negotiate_unix_fd = true;
+			else
+				dbus->negotiate_unix_fd = false;
 
 			classic->auth_command = l_strdup(command);
 			classic->auth_state = WAITING_FOR_OK;
@@ -680,6 +688,8 @@ static struct l_dbus_message *classic_recv_message(struct l_dbus *dbus)
 	len = recv(fd, &hdr, DBUS_HEADER_SIZE, MSG_PEEK | MSG_DONTWAIT);
 	if (len != DBUS_HEADER_SIZE)
 		return NULL;
+	else if (len == 0)
+		close(fd);
 
 	header_size = align_len(DBUS_HEADER_SIZE + hdr.dbus1.field_length, 8);
 	header = l_malloc(header_size);
@@ -1033,7 +1043,8 @@ static const struct l_dbus_ops classic_ops = {
 	.name_acquire = classic_name_acquire,
 };
 
-static struct l_dbus *setup_dbus1(int fd, const char *guid)
+static struct l_dbus *setup_dbus1(int fd, const char *guid,
+				  const char *transport)
 {
 	static const unsigned char creds = 0x00;
 	char uid[6], hexuid[12], *ptr = hexuid;
@@ -1065,11 +1076,13 @@ static struct l_dbus *setup_dbus1(int fd, const char *guid)
 
 	dbus_init(dbus, fd);
 	dbus->guid = l_strdup(guid);
+	dbus->transport = l_strdup(transport);
 
 	classic->auth_command = l_strdup_printf("AUTH EXTERNAL %s\r\n", hexuid);
 	classic->auth_state = WAITING_FOR_OK;
 
-	dbus->negotiate_unix_fd = true;
+	if (!strcmp(transport, "unix"))
+		dbus->negotiate_unix_fd = true;
 	dbus->support_unix_fd = false;
 
 	l_io_set_read_handler(dbus->io, auth_read_handler, dbus, NULL);
@@ -1145,7 +1158,131 @@ static struct l_dbus *setup_unix(char *params)
 		return NULL;
 	}
 
-	return setup_dbus1(fd, guid);
+	return setup_dbus1(fd, guid, "unix");
+}
+
+static struct l_dbus *setup_tcp(char *params)
+{
+	struct addrinfo hints;
+	struct addrinfo *results, *rp;
+	fd_set rfds, wfds;
+	socklen_t optlen;
+	struct timeval tv;
+	char *host = NULL, *port = NULL, *family = NULL, *guid = NULL;
+	unsigned long port_number;
+	int i, err;
+	int fd = -1, socket_fd = -1, optval = -1;
+
+	while (params) {
+		char *key = strsep(&params, ",");
+		char *value;
+
+		if (!key)
+			break;
+
+		value = strchr(key, '=');
+		if (!value)
+			continue;
+
+		*value++ = '\0';
+
+		if (!strcmp(key, "host"))
+			host = value;
+		else if (!strcmp(key, "port"))
+			port = value;
+		else if (!strcmp(key, "family"))
+			family = value;
+		else if (!strcmp(key, "guid"))
+			guid = value;
+	}
+
+	if (!host || !port)
+		return NULL;
+
+	port_number = strtoul(port, NULL, 10);
+
+	if (port_number == 0 || port_number >= 65536)
+		return NULL;
+
+	memset(&hints, 0, sizeof(hints));
+
+	hints.ai_family = AF_UNSPEC;
+	if (family) {
+		if (!strcmp(family, "ipv4"))
+			hints.ai_family = AF_INET;
+		else if (!strcmp(family, "ipv6"))
+			hints.ai_family = AF_INET6;
+	}
+
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_flags = 0;
+	hints.ai_protocol = 0;
+
+	if (getaddrinfo(host, port, &hints, &results) != 0)
+		return NULL;
+
+	FD_ZERO(&rfds);
+	FD_ZERO(&wfds);
+	for (rp = results; rp != NULL; rp = rp->ai_next) {
+		fd = socket(rp->ai_family, rp->ai_socktype | SOCK_NONBLOCK, rp->ai_protocol);
+		if (fd < 0)
+			continue;
+
+		errno = 0;
+		if (connect(fd, rp->ai_addr, rp->ai_addrlen) == -1) {
+			err = errno;
+			if (err == EINPROGRESS) {
+				FD_SET(fd, &rfds);
+				FD_SET(fd, &wfds);
+			} else if (err == ECONNREFUSED){
+				close(fd);
+			}
+		}
+	}
+
+	freeaddrinfo(results);
+
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+
+	// Wait until sockets be ready, otherwise a timeout is thrown
+	if (select(fd + 1, &rfds, &wfds, NULL, &tv) == 0) {
+		close(fd);
+		return NULL;
+	}
+
+	for (i = 1; i < fd + 1; i++) {
+		if (!FD_ISSET(i, &wfds) && !FD_ISSET(i, &rfds))
+			continue;
+
+		optlen = sizeof(optval);
+
+		if (getsockopt(i,
+				SOL_SOCKET, SO_ERROR, &optval,
+				&optlen) == -1)
+			return NULL;
+
+		/**
+			* getsockopt() puts the errno value
+			* for connect into optval so 0 means
+			* no-error.
+			*/
+		if (optval == 0) {
+			socket_fd = i;
+		} else {
+			close(i);
+			return NULL;
+		}
+
+		/* Remove this socket from fd_set */
+		FD_CLR(i, &wfds);
+		FD_CLR(i, &rfds);
+	}
+
+	if (socket_fd < 0)
+		return NULL;
+
+	return setup_dbus1(socket_fd, guid, "tcp");
 }
 
 static struct l_dbus *setup_address(const char *address)
@@ -1170,6 +1307,9 @@ static struct l_dbus *setup_address(const char *address)
 			/* Function will modify params string */
 			dbus = setup_unix(params);
 			break;
+		} else if (!strcmp(transport, "tcp")) {
+			dbus = setup_tcp(params);
+			break;
 		}
 	}
 
@@ -1232,6 +1372,7 @@ LIB_EXPORT void l_dbus_destroy(struct l_dbus *dbus)
 
 	l_free(dbus->guid);
 	l_free(dbus->unique_name);
+	l_free(dbus->transport);
 
 	_dbus_object_tree_free(dbus->tree);
 
-- 
2.7.4


  reply	other threads:[~2019-04-15 12:23 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-31 14:00 [PATCH 0/2] Allow connection to a tcp dbus address Ramon Henrique
2019-03-31 14:00 ` [PATCH 1/2] dbus: Add support to tcp address Ramon Henrique
2019-04-09 16:44   ` Denis Kenzior
2019-03-31 14:00 ` [PATCH 2/2] unit: dbus: Add unit test to dbus " Ramon Henrique
2019-04-15 12:23 ` [PATCH v1 0/2] Allow connection to a tcp dbus address Ramon Ribeiro
2019-04-15 12:23   ` Ramon Ribeiro [this message]
2019-04-15 16:59     ` [PATCH v1 1/2] dbus: Add support to tcp address Denis Kenzior
2019-04-15 12:23   ` [PATCH v1 2/2] unit: dbus: Add unit test to dbus " Ramon Ribeiro
2019-04-16 13:05   ` [PATCH v2 0/2] Allow connection to a tcp dbus address Ramon Ribeiro
2019-04-16 13:05     ` [PATCH v2 1/2] dbus: Add support to tcp address Ramon Ribeiro
2019-04-17 20:13       ` Denis Kenzior
2019-04-16 13:05     ` [PATCH v2 2/2] unit: dbus: Add unit test to dbus " Ramon Ribeiro

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1555331007-26977-2-git-send-email-rhpr@cesar.org.br \
    --to=rhpr@cesar.org.br \
    --cc=ell@lists.01.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.