stream: Separate TCP/Unix stream helpers from stream/service implementations
authorMartin Willi <martin@revosec.ch>
Fri, 11 Oct 2013 13:32:10 +0000 (15:32 +0200)
committerMartin Willi <martin@revosec.ch>
Wed, 4 Jun 2014 13:53:00 +0000 (15:53 +0200)
This allows us to disable Unix sockets cleanly on Windows. Replaces some
read/write calls with recv/send counterparts, as Winsock does not like
read/writes.

16 files changed:
src/libstrongswan/Android.mk
src/libstrongswan/Makefile.am
src/libstrongswan/networking/streams/stream.c
src/libstrongswan/networking/streams/stream.h
src/libstrongswan/networking/streams/stream_manager.c
src/libstrongswan/networking/streams/stream_service.c
src/libstrongswan/networking/streams/stream_service.h
src/libstrongswan/networking/streams/stream_service_tcp.c [new file with mode: 0644]
src/libstrongswan/networking/streams/stream_service_tcp.h [new file with mode: 0644]
src/libstrongswan/networking/streams/stream_service_unix.c [new file with mode: 0644]
src/libstrongswan/networking/streams/stream_service_unix.h [new file with mode: 0644]
src/libstrongswan/networking/streams/stream_tcp.c [new file with mode: 0644]
src/libstrongswan/networking/streams/stream_tcp.h [new file with mode: 0644]
src/libstrongswan/networking/streams/stream_unix.c [new file with mode: 0644]
src/libstrongswan/networking/streams/stream_unix.h [new file with mode: 0644]
src/libstrongswan/utils/windows.h

index 1840ad2..1310716 100644 (file)
@@ -27,8 +27,10 @@ credentials/sets/callback_cred.c credentials/auth_cfg.c database/database.c \
 database/database_factory.c fetcher/fetcher.c fetcher/fetcher_manager.c eap/eap.c \
 ipsec/ipsec_types.c \
 networking/host.c networking/host_resolver.c networking/packet.c \
-networking/tun_device.c networking/streams/stream.c \
-networking/streams/stream_service.c networking/streams/stream_manager.c \
+networking/tun_device.c networking/streams/stream_manager.c \
+networking/streams/stream.c networking/streams/stream_service.c \
+networking/streams/stream_tcp.c networking/streams/stream_service_tcp.c \
+networking/streams/stream_unix.c networking/streams/stream_service_unix.c \
 pen/pen.c plugins/plugin_loader.c plugins/plugin_feature.c processing/jobs/job.c \
 processing/jobs/callback_job.c processing/processor.c processing/scheduler.c \
 processing/watcher.c resolver/resolver_manager.c resolver/rr_set.c \
index 711676a..df1f026 100644 (file)
@@ -25,8 +25,9 @@ credentials/sets/callback_cred.c credentials/auth_cfg.c database/database.c \
 database/database_factory.c fetcher/fetcher.c fetcher/fetcher_manager.c eap/eap.c \
 ipsec/ipsec_types.c \
 networking/host.c networking/host_resolver.c networking/packet.c \
-networking/tun_device.c networking/streams/stream.c \
-networking/streams/stream_service.c networking/streams/stream_manager.c \
+networking/tun_device.c networking/streams/stream_manager.c \
+networking/streams/stream.c networking/streams/stream_service.c \
+networking/streams/stream_tcp.c networking/streams/stream_service_tcp.c \
 pen/pen.c plugins/plugin_loader.c plugins/plugin_feature.c processing/jobs/job.c \
 processing/jobs/callback_job.c processing/processor.c processing/scheduler.c \
 processing/watcher.c resolver/resolver_manager.c resolver/rr_set.c \
@@ -38,6 +39,12 @@ utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \
 utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \
 utils/parser_helper.c utils/test.c utils/utils/strerror.c
 
+if !USE_WINDOWS
+  libstrongswan_la_SOURCES += \
+    networking/streams/stream_unix.c \
+    networking/streams/stream_service_unix.c
+endif
+
 # private header files
 noinst_HEADERS = \
 settings/settings_types.h
@@ -74,6 +81,8 @@ database/database.h database/database_factory.h fetcher/fetcher.h \
 fetcher/fetcher_manager.h eap/eap.h pen/pen.h ipsec/ipsec_types.h \
 networking/host.h networking/host_resolver.h networking/packet.h \
 networking/tun_device.h networking/streams/stream.h \
+networking/streams/stream_unix.h networking/streams/stream_service_unix.h \
+networking/streams/stream_tcp.h networking/streams/stream_service_tcp.h \
 networking/streams/stream_service.h networking/streams/stream_manager.h \
 resolver/resolver.h resolver/resolver_response.h resolver/rr_set.h \
 resolver/rr.h resolver/resolver_manager.h \
index f6fec0b..e49c35a 100644 (file)
@@ -16,7 +16,8 @@
 #include <library.h>
 #include <errno.h>
 #include <unistd.h>
-#include <limits.h>
+
+#include "stream.h"
 
 typedef struct private_stream_t private_stream_t;
 
@@ -65,7 +66,7 @@ METHOD(stream_t, read_, ssize_t,
 
                if (block)
                {
-                       ret = read(this->fd, buf, len);
+                       ret = recv(this->fd, buf, len, 0);
                }
                else
                {
@@ -116,7 +117,7 @@ METHOD(stream_t, write_, ssize_t,
        {
                if (block)
                {
-                       ret = write(this->fd, buf, len);
+                       ret = send(this->fd, buf, len, 0);
                }
                else
                {
@@ -287,129 +288,3 @@ stream_t *stream_create_from_fd(int fd)
 
        return &this->public;
 }
-
-/**
- * See header
- */
-int stream_parse_uri_unix(char *uri, struct sockaddr_un *addr)
-{
-       if (!strpfx(uri, "unix://"))
-       {
-               return -1;
-       }
-       uri += strlen("unix://");
-
-       memset(addr, 0, sizeof(*addr));
-       addr->sun_family = AF_UNIX;
-       strncpy(addr->sun_path, uri, sizeof(addr->sun_path));
-       addr->sun_path[sizeof(addr->sun_path)-1] = '\0';
-
-       return offsetof(struct sockaddr_un, sun_path) + strlen(addr->sun_path);
-}
-
-/**
- * See header
- */
-stream_t *stream_create_unix(char *uri)
-{
-       struct sockaddr_un addr;
-       int len, fd;
-
-       len = stream_parse_uri_unix(uri, &addr);
-       if (len == -1)
-       {
-               DBG1(DBG_NET, "invalid stream URI: '%s'", uri);
-               return NULL;
-       }
-       fd = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (fd < 0)
-       {
-               DBG1(DBG_NET, "opening socket '%s' failed: %s", uri, strerror(errno));
-               return NULL;
-       }
-       if (connect(fd, (struct sockaddr*)&addr, len) < 0)
-       {
-               DBG1(DBG_NET, "connecting to '%s' failed: %s", uri, strerror(errno));
-               close(fd);
-               return NULL;
-       }
-       return stream_create_from_fd(fd);
-}
-
-/**
- * See header.
- */
-int stream_parse_uri_tcp(char *uri, struct sockaddr *addr)
-{
-       char *pos, buf[128];
-       host_t *host;
-       u_long port;
-       int len;
-
-       if (!strpfx(uri, "tcp://"))
-       {
-               return -1;
-       }
-       uri += strlen("tcp://");
-       pos = strrchr(uri, ':');
-       if (!pos)
-       {
-               return -1;
-       }
-       if (*uri == '[' && pos > uri && *(pos - 1) == ']')
-       {
-               /* IPv6 URI */
-               snprintf(buf, sizeof(buf), "%.*s", (int)(pos - uri - 2), uri + 1);
-       }
-       else
-       {
-               snprintf(buf, sizeof(buf), "%.*s", (int)(pos - uri), uri);
-       }
-       port = strtoul(pos + 1, &pos, 10);
-       if (port == ULONG_MAX || *pos || port > 65535)
-       {
-               return -1;
-       }
-       host = host_create_from_dns(buf, AF_UNSPEC, port);
-       if (!host)
-       {
-               return -1;
-       }
-       len = *host->get_sockaddr_len(host);
-       memcpy(addr, host->get_sockaddr(host), len);
-       host->destroy(host);
-       return len;
-}
-
-/**
- * See header
- */
-stream_t *stream_create_tcp(char *uri)
-{
-       union {
-               struct sockaddr_in in;
-               struct sockaddr_in6 in6;
-               struct sockaddr sa;
-       } addr;
-       int fd, len;
-
-       len = stream_parse_uri_tcp(uri, &addr.sa);
-       if (len == -1)
-       {
-               DBG1(DBG_NET, "invalid stream URI: '%s'", uri);
-               return NULL;
-       }
-       fd = socket(addr.sa.sa_family, SOCK_STREAM, 0);
-       if (fd < 0)
-       {
-               DBG1(DBG_NET, "opening socket '%s' failed: %s", uri, strerror(errno));
-               return NULL;
-       }
-       if (connect(fd, &addr.sa, len))
-       {
-               DBG1(DBG_NET, "connecting to '%s' failed: %s", uri, strerror(errno));
-               close(fd);
-               return NULL;
-       }
-       return stream_create_from_fd(fd);
-}
index 3516d91..747bf65 100644 (file)
@@ -25,9 +25,6 @@ typedef struct stream_t stream_t;
 
 #include <library.h>
 
-#include <sys/un.h>
-#include <sys/socket.h>
-
 /**
  * Constructor function prototype for stream_t.
  *
@@ -138,54 +135,6 @@ struct stream_t {
 };
 
 /**
- * Create a stream for UNIX sockets.
- *
- * UNIX URIs start with unix://, followed by the socket path. For absolute
- * paths, an URI looks something like:
- *
- *   unix:///path/to/socket
- *
- * @param uri          UNIX socket specific URI, must start with "unix://"
- * @return                     stream instance, NULL on failure
- */
-stream_t *stream_create_unix(char *uri);
-
-/**
- * Helper function to parse a unix:// URI to a sockaddr
- *
- * @param uri          URI
- * @param addr         sockaddr
- * @return                     length of sockaddr, -1 on error
- */
-int stream_parse_uri_unix(char *uri, struct sockaddr_un *addr);
-
-/**
- * Create a stream for TCP sockets.
- *
- * TCP URIs start with tcp://, followed by a hostname (FQDN or IP), followed
- * by a colon separated port. A full TCP uri looks something like:
- *
- *   tcp://srv.example.com:5555
- *   tcp://0.0.0.0:1234
- *   tcp://[fec2::1]:7654
- *
- * There is no default port, so a colon after tcp:// is mandatory.
- *
- * @param uri          TCP socket specific URI, must start with "tcp://"
- * @return                     stream instance, NULL on failure
- */
-stream_t *stream_create_tcp(char *uri);
-
-/**
- * Helper function to parse a tcp:// URI to a sockaddr
- *
- * @param uri          URI
- * @param addr         sockaddr, large enough for URI
- * @return                     length of sockaddr, -1 on error
- */
-int stream_parse_uri_tcp(char *uri, struct sockaddr *addr);
-
-/**
  * Create a stream from a file descriptor.
  *
  * The file descriptor MUST be a socket for non-blocking operation.
index 2cbd612..8de243d 100644 (file)
 
 #include "stream_manager.h"
 
+#include "stream_tcp.h"
+#include "stream_service_tcp.h"
+#ifndef WIN32
+# include "stream_unix.h"
+# include "stream_service_unix.h"
+#endif
+
 #include <threading/rwlock.h>
 
 typedef struct private_stream_manager_t private_stream_manager_t;
@@ -193,10 +200,12 @@ METHOD(stream_manager_t, remove_service, void,
 METHOD(stream_manager_t, destroy, void,
        private_stream_manager_t *this)
 {
-       remove_stream(this, stream_create_unix);
        remove_stream(this, stream_create_tcp);
-       remove_service(this, stream_service_create_unix);
        remove_service(this, stream_service_create_tcp);
+#ifndef WIN32
+       remove_stream(this, stream_create_unix);
+       remove_service(this, stream_service_create_unix);
+#endif
 
        this->streams->destroy(this->streams);
        this->services->destroy(this->services);
@@ -226,10 +235,12 @@ stream_manager_t *stream_manager_create()
                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
        );
 
-       add_stream(this, "unix://", stream_create_unix);
        add_stream(this, "tcp://", stream_create_tcp);
-       add_service(this, "unix://", stream_service_create_unix);
        add_service(this, "tcp://", stream_service_create_tcp);
+#ifndef WIN32
+       add_stream(this, "unix://", stream_create_unix);
+       add_service(this, "unix://", stream_service_create_unix);
+#endif
 
        return &this->public;
 }
index 4e0eebd..7358c58 100644 (file)
 #include <threading/condvar.h>
 #include <processing/jobs/callback_job.h>
 
+#include "stream_service.h"
+
 #include <errno.h>
 #include <unistd.h>
-#include <sys/socket.h>
-#include <sys/un.h>
 #include <sys/stat.h>
 
 typedef struct private_stream_service_t private_stream_service_t;
@@ -235,98 +235,3 @@ stream_service_t *stream_service_create_from_fd(int fd)
 
        return &this->public;
 }
-
-/**
- * See header
- */
-stream_service_t *stream_service_create_unix(char *uri, int backlog)
-{
-       struct sockaddr_un addr;
-       mode_t old;
-       int fd, len;
-
-       len = stream_parse_uri_unix(uri, &addr);
-       if (len == -1)
-       {
-               DBG1(DBG_NET, "invalid stream URI: '%s'", uri);
-               return NULL;
-       }
-       if (!lib->caps->check(lib->caps, CAP_CHOWN))
-       {       /* required to chown(2) service socket */
-               DBG1(DBG_NET, "socket '%s' requires CAP_CHOWN capability", uri);
-               return NULL;
-       }
-       fd = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (fd == -1)
-       {
-               DBG1(DBG_NET, "opening socket '%s' failed: %s", uri, strerror(errno));
-               return NULL;
-       }
-       unlink(addr.sun_path);
-
-       old = umask(S_IRWXO);
-       if (bind(fd, (struct sockaddr*)&addr, len) < 0)
-       {
-               DBG1(DBG_NET, "binding socket '%s' failed: %s", uri, strerror(errno));
-               close(fd);
-               return NULL;
-       }
-       umask(old);
-       if (chown(addr.sun_path, lib->caps->get_uid(lib->caps),
-                         lib->caps->get_gid(lib->caps)) != 0)
-       {
-               DBG1(DBG_NET, "changing socket permissions for '%s' failed: %s",
-                        uri, strerror(errno));
-       }
-       if (listen(fd, backlog) < 0)
-       {
-               DBG1(DBG_NET, "listen on socket '%s' failed: %s", uri, strerror(errno));
-               unlink(addr.sun_path);
-               close(fd);
-               return NULL;
-       }
-       return stream_service_create_from_fd(fd);
-}
-
-/**
- * See header
- */
-stream_service_t *stream_service_create_tcp(char *uri, int backlog)
-{
-       union {
-               struct sockaddr_in in;
-               struct sockaddr_in6 in6;
-               struct sockaddr sa;
-       } addr;
-       int fd, len, on = 1;
-
-       len = stream_parse_uri_tcp(uri, &addr.sa);
-       if (len == -1)
-       {
-               DBG1(DBG_NET, "invalid stream URI: '%s'", uri);
-               return NULL;
-       }
-       fd = socket(addr.sa.sa_family, SOCK_STREAM, 0);
-       if (fd < 0)
-       {
-               DBG1(DBG_NET, "opening socket '%s' failed: %s", uri, strerror(errno));
-               return NULL;
-       }
-       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0)
-       {
-               DBG1(DBG_NET, "SO_REUSADDR on '%s' failed: %s", uri, strerror(errno));
-       }
-       if (bind(fd, &addr.sa, len) < 0)
-       {
-               DBG1(DBG_NET, "binding socket '%s' failed: %s", uri, strerror(errno));
-               close(fd);
-               return NULL;
-       }
-       if (listen(fd, backlog) < 0)
-       {
-               DBG1(DBG_NET, "listen on socket '%s' failed: %s", uri, strerror(errno));
-               close(fd);
-               return NULL;
-       }
-       return stream_service_create_from_fd(fd);
-}
index c8faba3..de2aaf7 100644 (file)
@@ -23,7 +23,6 @@
 
 typedef struct stream_service_t stream_service_t;
 
-#include <library.h>
 #include <processing/jobs/job.h>
 #include <networking/streams/stream.h>
 
@@ -83,22 +82,4 @@ struct stream_service_t {
  */
 stream_service_t *stream_service_create_from_fd(int fd);
 
-/**
- * Create a service instance for UNIX sockets.
- *
- * @param uri          UNIX socket specific URI, must start with "unix://"
- * @param backlog      size of the backlog queue, as passed to listen()
- * @return                     stream_service instance, NULL on failure
- */
-stream_service_t *stream_service_create_unix(char *uri, int backlog);
-
-/**
- * Create a service instance for TCP sockets.
- *
- * @param uri          TCP socket specific URI, must start with "tcp://"
- * @param backlog      size of the backlog queue, as passed to listen()
- * @return                     stream_service instance, NULL on failure
- */
-stream_service_t *stream_service_create_tcp(char *uri, int backlog);
-
 #endif /** STREAM_SERVICE_H_ @}*/
diff --git a/src/libstrongswan/networking/streams/stream_service_tcp.c b/src/libstrongswan/networking/streams/stream_service_tcp.c
new file mode 100644 (file)
index 0000000..4082834
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <library.h>
+#include <networking/streams/stream_tcp.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+/**
+ * See header
+ */
+stream_service_t *stream_service_create_tcp(char *uri, int backlog)
+{
+       union {
+               struct sockaddr_in in;
+               struct sockaddr_in6 in6;
+               struct sockaddr sa;
+       } addr;
+       int fd, len, on = 1;
+
+       len = stream_parse_uri_tcp(uri, &addr.sa);
+       if (len == -1)
+       {
+               DBG1(DBG_NET, "invalid stream URI: '%s'", uri);
+               return NULL;
+       }
+       fd = socket(addr.sa.sa_family, SOCK_STREAM, 0);
+       if (fd < 0)
+       {
+               DBG1(DBG_NET, "opening socket '%s' failed: %s", uri, strerror(errno));
+               return NULL;
+       }
+       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) != 0)
+       {
+               DBG1(DBG_NET, "SO_REUSADDR on '%s' failed: %s", uri, strerror(errno));
+       }
+       if (bind(fd, &addr.sa, len) < 0)
+       {
+               DBG1(DBG_NET, "binding socket '%s' failed: %s", uri, strerror(errno));
+               close(fd);
+               return NULL;
+       }
+       if (listen(fd, backlog) < 0)
+       {
+               DBG1(DBG_NET, "listen on socket '%s' failed: %s", uri, strerror(errno));
+               close(fd);
+               return NULL;
+       }
+       return stream_service_create_from_fd(fd);
+}
diff --git a/src/libstrongswan/networking/streams/stream_service_tcp.h b/src/libstrongswan/networking/streams/stream_service_tcp.h
new file mode 100644 (file)
index 0000000..f63f007
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup stream_service_tcp stream_service_tcp
+ * @{ @ingroup stream
+ */
+
+#ifndef STREAM_SERVICE_TCP_H_
+#define STREAM_SERVICE_TCP_H_
+
+/**
+ * Create a service instance for TCP sockets.
+ *
+ * @param uri          TCP socket specific URI, must start with "tcp://"
+ * @param backlog      size of the backlog queue, as passed to listen()
+ * @return                     stream_service instance, NULL on failure
+ */
+stream_service_t *stream_service_create_tcp(char *uri, int backlog);
+
+#endif /** STREAM_SERVICE_TCP_H_ @}*/
diff --git a/src/libstrongswan/networking/streams/stream_service_unix.c b/src/libstrongswan/networking/streams/stream_service_unix.c
new file mode 100644 (file)
index 0000000..1ed27c4
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <library.h>
+#include <networking/streams/stream_unix.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+
+/**
+ * See header
+ */
+stream_service_t *stream_service_create_unix(char *uri, int backlog)
+{
+       struct sockaddr_un addr;
+       mode_t old;
+       int fd, len;
+
+       len = stream_parse_uri_unix(uri, &addr);
+       if (len == -1)
+       {
+               DBG1(DBG_NET, "invalid stream URI: '%s'", uri);
+               return NULL;
+       }
+       if (!lib->caps->check(lib->caps, CAP_CHOWN))
+       {       /* required to chown(2) service socket */
+               DBG1(DBG_NET, "socket '%s' requires CAP_CHOWN capability", uri);
+               return NULL;
+       }
+       fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (fd == -1)
+       {
+               DBG1(DBG_NET, "opening socket '%s' failed: %s", uri, strerror(errno));
+               return NULL;
+       }
+       unlink(addr.sun_path);
+
+       old = umask(S_IRWXO);
+       if (bind(fd, (struct sockaddr*)&addr, len) < 0)
+       {
+               DBG1(DBG_NET, "binding socket '%s' failed: %s", uri, strerror(errno));
+               close(fd);
+               return NULL;
+       }
+       umask(old);
+       if (chown(addr.sun_path, lib->caps->get_uid(lib->caps),
+                         lib->caps->get_gid(lib->caps)) != 0)
+       {
+               DBG1(DBG_NET, "changing socket permissions for '%s' failed: %s",
+                        uri, strerror(errno));
+       }
+       if (listen(fd, backlog) < 0)
+       {
+               DBG1(DBG_NET, "listen on socket '%s' failed: %s", uri, strerror(errno));
+               unlink(addr.sun_path);
+               close(fd);
+               return NULL;
+       }
+       return stream_service_create_from_fd(fd);
+}
diff --git a/src/libstrongswan/networking/streams/stream_service_unix.h b/src/libstrongswan/networking/streams/stream_service_unix.h
new file mode 100644 (file)
index 0000000..14c09cb
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup stream_service_unix stream_service_unix
+ * @{ @ingroup stream
+ */
+
+#ifndef STREAM_SERVICE_UNIX_H_
+#define STREAM_SERVICE_UNIX_H_
+
+/**
+ * Create a service instance for UNIX sockets.
+ *
+ * @param uri          UNIX socket specific URI, must start with "unix://"
+ * @param backlog      size of the backlog queue, as passed to listen()
+ * @return                     stream_service instance, NULL on failure
+ */
+stream_service_t *stream_service_create_unix(char *uri, int backlog);
+
+/**
+ * Create a service instance for TCP sockets.
+ *
+ * @param uri          TCP socket specific URI, must start with "tcp://"
+ * @param backlog      size of the backlog queue, as passed to listen()
+ * @return                     stream_service instance, NULL on failure
+ */
+stream_service_t *stream_service_create_tcp(char *uri, int backlog);
+
+#endif /** STREAM_SERVICE_UNIX_H_ @}*/
diff --git a/src/libstrongswan/networking/streams/stream_tcp.c b/src/libstrongswan/networking/streams/stream_tcp.c
new file mode 100644 (file)
index 0000000..5459145
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <library.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "stream_tcp.h"
+
+/**
+ * See header.
+ */
+int stream_parse_uri_tcp(char *uri, struct sockaddr *addr)
+{
+       char *pos, buf[128];
+       host_t *host;
+       u_long port;
+       int len;
+
+       if (!strpfx(uri, "tcp://"))
+       {
+               return -1;
+       }
+       uri += strlen("tcp://");
+       pos = strrchr(uri, ':');
+       if (!pos)
+       {
+               return -1;
+       }
+       if (*uri == '[' && pos > uri && *(pos - 1) == ']')
+       {
+               /* IPv6 URI */
+               snprintf(buf, sizeof(buf), "%.*s", (int)(pos - uri - 2), uri + 1);
+       }
+       else
+       {
+               snprintf(buf, sizeof(buf), "%.*s", (int)(pos - uri), uri);
+       }
+       port = strtoul(pos + 1, &pos, 10);
+       if (port == ULONG_MAX || *pos || port > 65535)
+       {
+               return -1;
+       }
+       host = host_create_from_dns(buf, AF_UNSPEC, port);
+       if (!host)
+       {
+               return -1;
+       }
+       len = *host->get_sockaddr_len(host);
+       memcpy(addr, host->get_sockaddr(host), len);
+       host->destroy(host);
+       return len;
+}
+
+/**
+ * See header
+ */
+stream_t *stream_create_tcp(char *uri)
+{
+       union {
+               struct sockaddr_in in;
+               struct sockaddr_in6 in6;
+               struct sockaddr sa;
+       } addr;
+       int fd, len;
+
+       len = stream_parse_uri_tcp(uri, &addr.sa);
+       if (len == -1)
+       {
+               DBG1(DBG_NET, "invalid stream URI: '%s'", uri);
+               return NULL;
+       }
+       fd = socket(addr.sa.sa_family, SOCK_STREAM, 0);
+       if (fd < 0)
+       {
+               DBG1(DBG_NET, "opening socket '%s' failed: %s", uri, strerror(errno));
+               return NULL;
+       }
+       if (connect(fd, &addr.sa, len))
+       {
+               DBG1(DBG_NET, "connecting to '%s' failed: %s", uri, strerror(errno));
+               close(fd);
+               return NULL;
+       }
+       return stream_create_from_fd(fd);
+}
diff --git a/src/libstrongswan/networking/streams/stream_tcp.h b/src/libstrongswan/networking/streams/stream_tcp.h
new file mode 100644 (file)
index 0000000..5bf6c82
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup stream_tcp stream_tcp
+ * @{ @ingroup streams
+ */
+
+#ifndef STREAM_TCP_H_
+#define STREAM_TCP_H_
+
+#include <library.h>
+
+/**
+ * Create a stream for TCP sockets.
+ *
+ * TCP URIs start with tcp://, followed by a hostname (FQDN or IP), followed
+ * by a colon separated port. A full TCP uri looks something like:
+ *
+ *   tcp://srv.example.com:5555
+ *   tcp://0.0.0.0:1234
+ *   tcp://[fec2::1]:7654
+ *
+ * There is no default port, so a colon after tcp:// is mandatory.
+ *
+ * @param uri          TCP socket specific URI, must start with "tcp://"
+ * @return                     stream instance, NULL on failure
+ */
+stream_t *stream_create_tcp(char *uri);
+
+/**
+ * Helper function to parse a tcp:// URI to a sockaddr
+ *
+ * @param uri          URI
+ * @param addr         sockaddr, large enough for URI
+ * @return                     length of sockaddr, -1 on error
+ */
+int stream_parse_uri_tcp(char *uri, struct sockaddr *addr);
+
+#endif /** STREAM_TCP_H_ @}*/
diff --git a/src/libstrongswan/networking/streams/stream_unix.c b/src/libstrongswan/networking/streams/stream_unix.c
new file mode 100644 (file)
index 0000000..13e56bc
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <library.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "stream_unix.h"
+
+/**
+ * See header
+ */
+int stream_parse_uri_unix(char *uri, struct sockaddr_un *addr)
+{
+       if (!strpfx(uri, "unix://"))
+       {
+               return -1;
+       }
+       uri += strlen("unix://");
+
+       memset(addr, 0, sizeof(*addr));
+       addr->sun_family = AF_UNIX;
+       strncpy(addr->sun_path, uri, sizeof(addr->sun_path));
+       addr->sun_path[sizeof(addr->sun_path)-1] = '\0';
+
+       return offsetof(struct sockaddr_un, sun_path) + strlen(addr->sun_path);
+}
+
+/**
+ * See header
+ */
+stream_t *stream_create_unix(char *uri)
+{
+       struct sockaddr_un addr;
+       int len, fd;
+
+       len = stream_parse_uri_unix(uri, &addr);
+       if (len == -1)
+       {
+               DBG1(DBG_NET, "invalid stream URI: '%s'", uri);
+               return NULL;
+       }
+       fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (fd < 0)
+       {
+               DBG1(DBG_NET, "opening socket '%s' failed: %s", uri, strerror(errno));
+               return NULL;
+       }
+       if (connect(fd, (struct sockaddr*)&addr, len) < 0)
+       {
+               DBG1(DBG_NET, "connecting to '%s' failed: %s", uri, strerror(errno));
+               close(fd);
+               return NULL;
+       }
+       return stream_create_from_fd(fd);
+}
diff --git a/src/libstrongswan/networking/streams/stream_unix.h b/src/libstrongswan/networking/streams/stream_unix.h
new file mode 100644 (file)
index 0000000..5204251
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup stream_unix stream_unix
+ * @{ @ingroup streams
+ */
+
+#ifndef STREAM_UNIX_H_
+#define STREAM_UNIX_H_
+
+#include <sys/un.h>
+
+/**
+ * Create a stream for UNIX sockets.
+ *
+ * UNIX URIs start with unix://, followed by the socket path. For absolute
+ * paths, an URI looks something like:
+ *
+ *   unix:///path/to/socket
+ *
+ * @param uri          UNIX socket specific URI, must start with "unix://"
+ * @return                     stream instance, NULL on failure
+ */
+stream_t *stream_create_unix(char *uri);
+
+/**
+ * Helper function to parse a unix:// URI to a sockaddr
+ *
+ * @param uri          URI
+ * @param addr         sockaddr
+ * @return                     length of sockaddr, -1 on error
+ */
+int stream_parse_uri_unix(char *uri, struct sockaddr_un *addr);
+
+#endif /** STREAM_UNIX_H_ @}*/
index 9761c06..8c009ca 100644 (file)
@@ -262,6 +262,12 @@ int socketpair(int domain, int type, int protocol, int sv[2]);
 #define EWOULDBLOCK EAGAIN
 
 /**
+ * ECONNRESET is mapped to something arbitrary. It is returned by
+ * stream->read_all() but should not be mapped from a send/recv WSA error.
+ */
+#define ECONNRESET ENXIO
+
+/**
  * recv(2) with support for MSG_DONTWAIT
  */
 #define recv(...) windows_recv(__VA_ARGS__)