[PATCH v4 01/12] sio: introduce sio_uri_to_addr

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Thu Jan 31 00:28:27 MSK 2019


The function parses string URI consisting of either IP and port,
or UNIX socket address, and stores the result into struct
sockaddr.
---
 src/CMakeLists.txt       |  2 +-
 src/sio.c                | 41 +++++++++++++++++
 src/sio.h                |  7 +++
 test/unit/CMakeLists.txt |  3 ++
 test/unit/sio.c          | 96 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 148 insertions(+), 1 deletion(-)
 create mode 100644 test/unit/sio.c

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 04de5ad04..38bd576e6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -120,7 +120,7 @@ endif ()
 
 add_library(core STATIC ${core_sources})
 target_link_libraries(core
-    salad small
+    salad small uri
     ${LIBEV_LIBRARIES}
     ${LIBEIO_LIBRARIES}
     ${LIBCORO_LIBRARIES}
diff --git a/src/sio.c b/src/sio.c
index 613cd9412..419f4e0f4 100644
--- a/src/sio.c
+++ b/src/sio.c
@@ -36,9 +36,11 @@
 #include <limits.h>
 #include <netinet/in.h> /* TCP_NODELAY */
 #include <netinet/tcp.h> /* TCP_NODELAY */
+#include <arpa/inet.h>
 #include "say.h"
 #include "trivia/util.h"
 #include "exception.h"
+#include "uri.h"
 
 const char *
 sio_socketname(int fd)
@@ -321,3 +323,42 @@ sio_strfaddr(struct sockaddr *addr, socklen_t addrlen)
 	}
 	return name;
 }
+
+int
+sio_uri_to_addr(const char *uri, struct sockaddr *addr)
+{
+	struct uri u;
+	if (uri_parse(&u, uri) != 0 || u.service == NULL)
+		goto invalid_uri;
+	if (u.host_len == strlen(URI_HOST_UNIX) &&
+	    memcmp(u.host, URI_HOST_UNIX, u.host_len) == 0) {
+		struct sockaddr_un *un = (struct sockaddr_un *) addr;
+		if (u.service_len + 1 > sizeof(un->sun_path))
+			goto invalid_uri;
+		memcpy(un->sun_path, u.service, u.service_len);
+		un->sun_path[u.service_len] = 0;
+		un->sun_family = AF_UNIX;
+		return 0;
+	}
+	in_addr_t iaddr;
+	if (u.host_len == 0) {
+		iaddr = htonl(INADDR_ANY);
+	} else if (u.host_len == 9 && memcmp("localhost", u.host, 9) == 0) {
+		iaddr = htonl(INADDR_LOOPBACK);
+	} else {
+		iaddr = inet_addr(tt_cstr(u.host, u.host_len));
+		if (iaddr == (in_addr_t) -1)
+			goto invalid_uri;
+	}
+	struct sockaddr_in *in = (struct sockaddr_in *) addr;
+	int port = htons(atoi(u.service));
+	memset(in, 0, sizeof(*in));
+	in->sin_family = AF_INET;
+	in->sin_addr.s_addr = iaddr;
+	in->sin_port = port;
+	return 0;
+
+invalid_uri:
+	diag_set(SocketError, sio_socketname(-1), "invalid uri \"%s\"", uri);
+	return -1;
+}
diff --git a/src/sio.h b/src/sio.h
index 3067dc111..27988a232 100644
--- a/src/sio.h
+++ b/src/sio.h
@@ -203,6 +203,13 @@ ssize_t sio_sendto(int fd, const void *buf, size_t len, int flags,
 ssize_t sio_recvfrom(int fd, void *buf, size_t len, int flags,
 		     struct sockaddr *src_addr, socklen_t *addrlen);
 
+/**
+ * Convert a string URI like "ip:port" or "unix/:path" to
+ * sockaddr_in/un structure.
+ */
+int
+sio_uri_to_addr(const char *uri, struct sockaddr *addr);
+
 #if defined(__cplusplus)
 } /* extern "C" */
 #endif /* defined(__cplusplus) */
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index 0025d3611..16739f75d 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -203,3 +203,6 @@ add_executable(checkpoint_schedule.test
     ${PROJECT_SOURCE_DIR}/src/box/checkpoint_schedule.c
 )
 target_link_libraries(checkpoint_schedule.test m unit)
+
+add_executable(sio.test sio.c)
+target_link_libraries(sio.test unit core)
diff --git a/test/unit/sio.c b/test/unit/sio.c
new file mode 100644
index 000000000..84a86aac3
--- /dev/null
+++ b/test/unit/sio.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2010-2019, Tarantool AUTHORS, please see AUTHORS file.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "unit.h"
+#include "memory.h"
+#include "fiber.h"
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include "sio.h"
+
+static void
+check_uri_to_addr(void)
+{
+	header();
+	plan(18);
+	struct sockaddr_storage storage;
+	struct sockaddr *addr = (struct sockaddr *) &storage;
+	struct sockaddr_un *un = (struct sockaddr_un *) addr;
+	struct sockaddr_in *in = (struct sockaddr_in *) addr;
+	isnt(0, sio_uri_to_addr("invalid uri", addr),
+	     "invalid uri is detected");
+
+	char long_path[1000];
+	char *pos = long_path + sprintf(long_path, "unix/:/");
+	memset(pos, 'a', 900);
+	pos[900] = 0;
+	isnt(0, sio_uri_to_addr(long_path, addr), "too long UNIX path");
+
+	is(0, sio_uri_to_addr("unix/:/normal_path", addr), "UNIX");
+	is(0, strcmp(un->sun_path, "/normal_path"), "UNIX path");
+	is(AF_UNIX, un->sun_family, "UNIX family");
+
+	is(0, sio_uri_to_addr("localhost:1234", addr), "localhost");
+	is(AF_INET, in->sin_family, "localhost family");
+	is(htonl(INADDR_LOOPBACK), in->sin_addr.s_addr, "localhost address");
+	is(htons(1234), in->sin_port, "localhost port");
+
+	is(0, sio_uri_to_addr("5678", addr), "'any'");
+	is(AF_INET, in->sin_family, "'any' family");
+	is(htonl(INADDR_ANY), in->sin_addr.s_addr, "'any' address");
+	is(htons(5678), in->sin_port, "'any' port");
+
+	is(0, sio_uri_to_addr("192.168.0.1:9101", addr), "IP");
+	is(AF_INET, in->sin_family, "IP family");
+	is(inet_addr("192.168.0.1"), in->sin_addr.s_addr, "IP address");
+	is(htons(9101), in->sin_port, "IP port");
+
+	isnt(0, sio_uri_to_addr("192.168.0.300:1112", addr), "invalid IP");
+
+	check_plan();
+	footer();
+}
+
+int
+main(void)
+{
+	memory_init();
+	fiber_init(fiber_c_invoke);
+
+	header();
+	plan(1);
+	check_uri_to_addr();
+	int rc = check_plan();
+	footer();
+
+	fiber_free();
+	memory_free();
+	return rc;
+}
-- 
2.17.2 (Apple Git-113)




More information about the Tarantool-patches mailing list