ARG_ENABL_SET([unbound], [enable UNBOUND resolver plugin to perform DNS queries via libunbound. Requires libldns and libunbound.])
ARG_ENABL_SET([soup], [enable soup fetcher plugin to fetch from HTTP via libsoup. Requires libsoup.])
ARG_ENABL_SET([ldap], [enable LDAP fetching plugin to fetch files via libldap. Requires openLDAP.])
+ARG_ENABL_SET([tls-stream], [enable libtls based TLS streams and services.])
ARG_DISBL_SET([aes], [disable AES software implementation plugin.])
ARG_DISBL_SET([des], [disable DES/3DES software implementation plugin.])
ARG_ENABL_SET([blowfish], [enable Blowfish software implementation plugin.])
simaka=true;
fi
-if test x$eap_tls = xtrue -o x$eap_ttls = xtrue -o x$eap_peap = xtrue; then
+if test x$eap_tls = xtrue -o x$eap_ttls = xtrue -o x$eap_peap = xtrue -o x$tls_stream = xtrue; then
tls=true;
fi
ADD_PLUGIN([soup], [s charon scripts nm cmd])
ADD_PLUGIN([unbound], [s charon scripts])
ADD_PLUGIN([ldap], [s charon scepclient scripts nm cmd])
+ADD_PLUGIN([tls-stream], [s charon])
ADD_PLUGIN([mysql], [s charon pool manager medsrv attest])
ADD_PLUGIN([sqlite], [s charon pool manager medsrv attest])
ADD_PLUGIN([pkcs11], [s charon pki nm cmd])
AM_CONDITIONAL(USE_UNBOUND, test x$unbound = xtrue)
AM_CONDITIONAL(USE_SOUP, test x$soup = xtrue)
AM_CONDITIONAL(USE_LDAP, test x$ldap = xtrue)
+AM_CONDITIONAL(USE_TLS_STREAM, test x$tls_stream = xtrue)
AM_CONDITIONAL(USE_AES, test x$aes = xtrue)
AM_CONDITIONAL(USE_DES, test x$des = xtrue)
AM_CONDITIONAL(USE_BLOWFISH, test x$blowfish = xtrue)
src/libstrongswan/plugins/unbound/Makefile
src/libstrongswan/plugins/soup/Makefile
src/libstrongswan/plugins/ldap/Makefile
+ src/libstrongswan/plugins/tls_stream/Makefile
src/libstrongswan/plugins/mysql/Makefile
src/libstrongswan/plugins/sqlite/Makefile
src/libstrongswan/plugins/padlock/Makefile
library.lo : $(top_builddir)/config.status
-libstrongswan_la_LIBADD = $(PTHREADLIB) $(DLLIB) $(BTLIB) $(SOCKLIB) $(RTLIB) $(BFDLIB) $(UNWINDLIB)
+libstrongswan_la_LIBADD = $(PTHREADLIB) $(DLLIB) $(BTLIB) $(SOCKLIB) $(RTLIB) $(BFDLIB) $(UNWINDLIB) $(top_builddir)/src/libtls/libtls.la
INCLUDES = -I$(top_srcdir)/src/libstrongswan
AM_CFLAGS = \
endif
endif
+if USE_TLS_STREAM
+ SUBDIRS += plugins/tls_stream
+if MONOLITHIC
+ libstrongswan_la_LIBADD += plugins/tls_stream/libstrongswan-tls-stream.la
+endif
+endif
+
if USE_MYSQL
SUBDIRS += plugins/mysql
if MONOLITHIC
--- /dev/null
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libtls
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-tls-stream.la
+else
+plugin_LTLIBRARIES = libstrongswan-tls-stream.la
+libstrongswan_tls_stream_la_LIBADD = $(top_builddir)/src/libtls/libtls.la
+endif
+
+libstrongswan_tls_stream_la_SOURCES = \
+ tls_stream_plugin.h tls_stream_plugin.c \
+ tls_stream.h tls_stream.c \
+ tls_stream_service.h tls_stream_service.c
+
+libstrongswan_tls_stream_la_LDFLAGS = -module -avoid-version
--- /dev/null
+/*
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#include "tls_stream.h"
+
+#include <tls_socket.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+
+typedef struct private_tls_stream_t private_tls_stream_t;
+
+/**
+ * Private data of an tls_stream_t object.
+ */
+struct private_tls_stream_t {
+
+ /**
+ * Public tls_stream_t interface.
+ */
+ stream_t public;
+
+ /**
+ * Underlying TLS socket.
+ */
+ tls_socket_t *tls;
+
+ /**
+ * FD for encrypted data
+ */
+ int fd;
+
+ /**
+ * Callback if data is ready to read
+ */
+ stream_cb_t read_cb;
+
+ /**
+ * Data for read-ready callback
+ */
+ void *read_data;
+
+ /**
+ * Callback if write is non-blocking
+ */
+ stream_cb_t write_cb;
+
+ /**
+ * Data for write-ready callback
+ */
+ void *write_data;
+};
+
+METHOD(stream_t, read_, ssize_t,
+ private_tls_stream_t *this, void *buf, size_t len, bool block)
+{
+ return this->tls->read(this->tls, buf, len, block);
+}
+
+METHOD(stream_t, read_all, bool,
+ private_tls_stream_t *this, void *buf, size_t len)
+{
+ ssize_t ret;
+
+ while (len)
+ {
+ ret = read_(this, buf, len, TRUE);
+ if (ret < 0)
+ {
+ return FALSE;
+ }
+ if (ret == 0)
+ {
+ errno = ECONNRESET;
+ return FALSE;
+ }
+ len -= ret;
+ buf += ret;
+ }
+ return TRUE;
+}
+
+METHOD(stream_t, write_, ssize_t,
+ private_tls_stream_t *this, void *buf, size_t len, bool block)
+{
+ return this->tls->write(this->tls, buf, len);
+}
+
+METHOD(stream_t, write_all, bool,
+ private_tls_stream_t *this, void *buf, size_t len)
+{
+ ssize_t ret;
+
+ while (len)
+ {
+ ret = write_(this, buf, len, TRUE);
+ if (ret < 0)
+ {
+ return FALSE;
+ }
+ if (ret == 0)
+ {
+ errno = ECONNRESET;
+ return FALSE;
+ }
+ len -= ret;
+ buf += ret;
+ }
+ return TRUE;
+}
+
+/**
+ * Remove a registered watcher
+ */
+static void remove_watcher(private_tls_stream_t *this)
+{
+ if (this->read_cb || this->write_cb)
+ {
+ lib->watcher->remove(lib->watcher, this->fd);
+ }
+}
+
+/**
+ * Watcher callback
+ */
+static bool watch(private_tls_stream_t *this, int fd, watcher_event_t event)
+{
+ bool keep = FALSE;
+ stream_cb_t cb;
+
+ switch (event)
+ {
+ case WATCHER_READ:
+ cb = this->read_cb;
+ this->read_cb = NULL;
+ keep = cb(this->read_data, &this->public);
+ if (keep)
+ {
+ this->read_cb = cb;
+ }
+ break;
+ case WATCHER_WRITE:
+ cb = this->write_cb;
+ this->write_cb = NULL;
+ keep = cb(this->write_data, &this->public);
+ if (keep)
+ {
+ this->write_cb = cb;
+ }
+ break;
+ case WATCHER_EXCEPT:
+ break;
+ }
+ return keep;
+}
+
+/**
+ * Register watcher for stream callbacks
+ */
+static void add_watcher(private_tls_stream_t *this)
+{
+ watcher_event_t events = 0;
+
+ if (this->read_cb)
+ {
+ events |= WATCHER_READ;
+ }
+ if (this->write_cb)
+ {
+ events |= WATCHER_WRITE;
+ }
+ if (events)
+ {
+ lib->watcher->add(lib->watcher, this->fd, events,
+ (watcher_cb_t)watch, this);
+ }
+}
+
+METHOD(stream_t, on_read, void,
+ private_tls_stream_t *this, stream_cb_t cb, void *data)
+{
+ remove_watcher(this);
+
+ this->read_cb = cb;
+ this->read_data = data;
+
+ add_watcher(this);
+}
+
+METHOD(stream_t, on_write, void,
+ private_tls_stream_t *this, stream_cb_t cb, void *data)
+{
+ remove_watcher(this);
+
+ this->write_cb = cb;
+ this->write_data = data;
+
+ add_watcher(this);
+}
+
+#if defined(HAVE_FOPENCOOKIE)
+
+/**
+ * Read callback for fopencookie()
+ */
+static ssize_t cookie_read(private_tls_stream_t *this, char *buf, size_t len)
+{
+ return this->tls->read(this->tls, buf, len, TRUE);
+}
+
+/**
+ * Write callback for fopencookie()
+ */
+static ssize_t cookie_write(private_tls_stream_t *this, char *buf, size_t len)
+{
+ return this->tls->write(this->tls, buf, len);
+}
+
+METHOD(stream_t, get_file, FILE*,
+ private_tls_stream_t *this)
+{
+ static cookie_io_functions_t cookie_funcs = {
+ .read = (void*)cookie_read,
+ .write = (void*)cookie_write,
+ .seek = NULL,
+ .close = NULL,
+ };
+ return fopencookie(this, "r+", cookie_funcs);
+}
+
+#elif defined(HAVE_FUNOPEN)
+
+/**
+ * Read callback for funopen()
+ */
+static int fun_read(private_tls_stream_t *this, char *buf, int len)
+{
+ return this->tls->read(this->tls, buf, len, TRUE);
+}
+
+/**
+ * Write callback for funopen()
+ */
+static int fun_write(private_tls_stream_t *this, char *buf, int len)
+{
+ return this->tls->write(this->tls, buf, len);
+}
+
+METHOD(stream_t, get_file, FILE*,
+ private_tls_stream_t *this)
+{
+ return funopen(this, (void*)fun_read, (void*)fun_write, NULL, NULL);
+}
+
+#else /* !HAVE_FOPENCOOKIE && !HAVE_FUNOPEN */
+
+METHOD(stream_t, get_file, FILE*,
+ private_tls_stream_t *this)
+{
+ return NULL;
+}
+
+#endif /* HAVE_FOPENCOOKIE/HAVE_FUNOPEN */
+
+METHOD(stream_t, destroy, void,
+ private_tls_stream_t *this)
+{
+ this->tls->destroy(this->tls);
+ close(this->fd);
+ free(this);
+}
+
+/**
+ * See header
+ */
+stream_t *tls_stream_create_from_fd(int fd, bool is_server,
+ identification_t *server,
+ tls_cache_t *cache)
+{
+ private_tls_stream_t *this;
+
+ INIT(this,
+ .public = {
+ .read = _read_,
+ .read_all = _read_all,
+ .on_read = _on_read,
+ .write = _write_,
+ .write_all = _write_all,
+ .on_write = _on_write,
+ .get_file = _get_file,
+ .destroy = _destroy,
+ },
+ .tls = tls_socket_create(is_server, server, NULL, fd, cache),
+ .fd = fd,
+ );
+
+ if (!this->tls)
+ {
+ free(this);
+ return NULL;
+ }
+ return &this->public;
+}
+
+/**
+ * See header.
+ */
+int tls_stream_parse_uri(char *uri, struct sockaddr *addr,
+ identification_t **server)
+{
+ identification_t *id;
+ char *pos, buf[256];
+ host_t *host;
+ u_long port;
+ int len;
+
+ if (!strncaseeq(uri, "tcp+tls://", strlen("tcp+tls://")))
+ {
+ return -1;
+ }
+ uri += strlen("tcp+tls://");
+ pos = strrchr(uri, '@');
+ if (!pos)
+ {
+ return -1;
+ }
+ id = identification_create_from_data(chunk_create(uri, pos - uri));
+ uri = pos + 1;
+ pos = strrchr(uri, ':');
+ if (!pos)
+ {
+ id->destroy(id);
+ 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)
+ {
+ id->destroy(id);
+ return -1;
+ }
+ host = host_create_from_dns(buf, AF_UNSPEC, port);
+ if (!host)
+ {
+ id->destroy(id);
+ return -1;
+ }
+ len = *host->get_sockaddr_len(host);
+ memcpy(addr, host->get_sockaddr(host), len);
+ host->destroy(host);
+ *server = id;
+ return len;
+}
+
+/**
+ * See header
+ */
+stream_t *tls_stream_create(char *uri)
+{
+ union {
+ struct sockaddr_in in;
+ struct sockaddr_in6 in6;
+ struct sockaddr sa;
+ } addr;
+ int fd, len;
+ identification_t *server;
+ stream_t *stream;
+
+ len = tls_stream_parse_uri(uri, &addr.sa, &server);
+ 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;
+ }
+ stream = tls_stream_create_from_fd(fd, FALSE, server, NULL);
+ server->destroy(server);
+ if (!stream)
+ {
+ close(fd);
+ }
+ return stream;
+}
--- /dev/null
+/*
+ * 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 tls_stream tls_stream
+ * @{ @ingroup tls
+ */
+
+#ifndef TLS_STREAM_H_
+#define TLS_STREAM_H_
+
+#include <library.h>
+#include <tls_cache.h>
+
+/**
+ * Helper function to parse a tcp+tls:// URI.
+ *
+ * @param uri URI to parse
+ * @param addr sockaddr, large enough for URI address
+ * @param server pointer receiving allocated server identity
+ * @return len of created addr, -1 on error
+ */
+int tls_stream_parse_uri(char *uri, struct sockaddr *addr,
+ identification_t **server);
+
+/**
+ * Helper function to create a stream from an FD and a server identity.
+ *
+ * @param fd file descripter
+ * @param is_server TRUE to act as TLS server, FALSE for client
+ * @param server server identity, gets cloned
+ * @param cache shared TLS session cache, if any
+ * @return client stream, NULL on error
+ */
+stream_t *tls_stream_create_from_fd(int fd, bool is_server,
+ identification_t *server,
+ tls_cache_t *cache);
+
+/**
+ * Create a tls_stream instance.
+ *
+ * The following URIs are currently accepted by this constructor:
+ * - tcp+tls://serverid@address:port
+ * Server authenticates with a certificate for serverid, no client auth.
+ *
+ * @param uri URI to create a stream for
+ * @return stream instance, NULL on error
+ */
+stream_t *tls_stream_create(char *uri);
+
+#endif /** TLS_STREAM_H_ @}*/
--- /dev/null
+/*
+ * 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 "tls_stream_plugin.h"
+#include "tls_stream.h"
+#include "tls_stream_service.h"
+
+#include <library.h>
+
+typedef struct private_tls_stream_plugin_t private_tls_stream_plugin_t;
+
+/**
+ * Private data of tls_stream_plugin
+ */
+struct private_tls_stream_plugin_t {
+
+ /**
+ * public functions
+ */
+ tls_stream_plugin_t public;
+};
+
+METHOD(plugin_t, get_name, char*,
+ private_tls_stream_plugin_t *this)
+{
+ return "tls-stream";
+}
+
+METHOD(plugin_t, get_features, int,
+ private_tls_stream_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_REGISTER(STREAM, tls_stream_create),
+ PLUGIN_PROVIDE(STREAM, "tcp+tls://"),
+ PLUGIN_REGISTER(STREAM_SERVICE, tls_stream_service_create),
+ PLUGIN_PROVIDE(STREAM_SERVICE, "tcp+tls://"),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ private_tls_stream_plugin_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *tls_stream_plugin_create()
+{
+ private_tls_stream_plugin_t *this;
+
+ INIT(this,
+ .public = {
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ },
+ );
+
+ return &this->public.plugin;
+}
--- /dev/null
+/*
+ * 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 tls_stream tls_stream
+ * @ingroup plugins
+ *
+ * @defgroup tls_stream_plugin tls_stream_plugin
+ * @{ @ingroup tls_stream
+ */
+
+#ifndef TLS_STREAM_PLUGIN_H_
+#define TLS_STREAM_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct tls_stream_plugin_t tls_stream_plugin_t;
+
+/**
+ * Plugin providing TLS protected streams and stream services.
+ */
+struct tls_stream_plugin_t {
+
+ /**
+ * Implements plugin interface.
+ */
+ plugin_t plugin;
+};
+
+#endif /** TLS_STREAM_PLUGIN_H_ @}*/
--- /dev/null
+/*
+ * 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 "tls_stream_service.h"
+#include "tls_stream.h"
+
+#include <threading/thread.h>
+#include <threading/mutex.h>
+#include <threading/condvar.h>
+#include <processing/jobs/callback_job.h>
+
+#include <unistd.h>
+#include <errno.h>
+
+typedef struct private_tls_stream_service_t private_tls_stream_service_t;
+
+/**
+ * Private data of an tls_stream_service_t object.
+ */
+struct private_tls_stream_service_t {
+
+ /**
+ * Public tls_stream_service_t interface.
+ */
+ stream_service_t public;
+
+ /**
+ * Underlying socket
+ */
+ int fd;
+
+ /**
+ * Accept callback
+ */
+ stream_service_cb_t cb;
+
+ /**
+ * Accept callback data
+ */
+ void *data;
+
+ /**
+ * Job priority to invoke callback with
+ */
+ job_priority_t prio;
+
+ /**
+ * Maximum number of parallel callback invocations
+ */
+ u_int cncrncy;
+
+ /**
+ * Currently active jobs
+ */
+ u_int active;
+
+ /**
+ * mutex to lock active counter
+ */
+ mutex_t *mutex;
+
+ /**
+ * Condvar to wait for callback termination
+ */
+ condvar_t *condvar;
+
+ /**
+ * Server identity
+ */
+ identification_t *server;
+
+ /**
+ * TLS session cache for this service
+ */
+ tls_cache_t *cache;
+};
+
+/**
+ * Data to pass to async accept job
+ */
+typedef struct {
+ /** callback function */
+ stream_service_cb_t cb;
+ /** callback data */
+ void *data;
+ /** accepted connection */
+ int fd;
+ /** reference to stream service */
+ private_tls_stream_service_t *this;
+} async_data_t;
+
+/**
+ * Clean up accept data
+ */
+static void destroy_async_data(async_data_t *data)
+{
+ private_tls_stream_service_t *this = data->this;
+
+ this->mutex->lock(this->mutex);
+ if (this->active-- == this->cncrncy)
+ {
+ /* leaving concurrency limit, restart accept()ing. */
+ this->public.on_accept(&this->public, this->cb, this->data,
+ this->prio, this->cncrncy);
+ }
+ this->condvar->signal(this->condvar);
+ this->mutex->unlock(this->mutex);
+
+ if (data->fd != -1)
+ {
+ close(data->fd);
+ }
+ free(data);
+}
+
+/**
+ * Async processing of accepted connection
+ */
+static job_requeue_t accept_async(async_data_t *data)
+{
+ stream_t *stream;
+
+ stream = tls_stream_create_from_fd(data->fd, TRUE, data->this->server,
+ data->this->cache);
+ if (stream)
+ {
+ /* FD is now owned by stream, don't close it during cleanup */
+ data->fd = -1;
+ thread_cleanup_push((void*)stream->destroy, stream);
+ thread_cleanup_pop(!data->cb(data->data, stream));
+ }
+ return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Watcher callback function
+ */
+static bool watch(private_tls_stream_service_t *this,
+ int fd, watcher_event_t event)
+{
+ async_data_t *data;
+ bool keep = TRUE;
+
+ INIT(data,
+ .cb = this->cb,
+ .data = this->data,
+ .fd = accept(fd, NULL, NULL),
+ .this = this,
+ );
+
+ if (data->fd != -1)
+ {
+ this->mutex->lock(this->mutex);
+ if (++this->active == this->cncrncy)
+ {
+ /* concurrency limit reached, stop accept()ing new connections */
+ keep = FALSE;
+ }
+ this->mutex->unlock(this->mutex);
+
+ lib->processor->queue_job(lib->processor,
+ (job_t*)callback_job_create_with_prio((void*)accept_async, data,
+ (void*)destroy_async_data, (callback_job_cancel_t)return_false,
+ this->prio));
+ }
+ else
+ {
+ free(data);
+ }
+ return keep;
+}
+
+METHOD(stream_service_t, on_accept, void,
+ private_tls_stream_service_t *this, stream_service_cb_t cb, void *data,
+ job_priority_t prio, u_int cncrncy)
+{
+ this->mutex->lock(this->mutex);
+
+ /* wait for all callbacks to return */
+ this->mutex->lock(this->mutex);
+ while (this->active)
+ {
+ this->condvar->wait(this->condvar, this->mutex);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (this->cb)
+ {
+ lib->watcher->remove(lib->watcher, this->fd);
+ }
+
+ this->cb = cb;
+ this->data = data;
+ if (prio <= JOB_PRIO_MAX)
+ {
+ this->prio = prio;
+ }
+ this->cncrncy = cncrncy;
+
+ if (this->cb)
+ {
+ lib->watcher->add(lib->watcher, this->fd,
+ WATCHER_READ, (watcher_cb_t)watch, this);
+ }
+
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(stream_service_t, destroy, void,
+ private_tls_stream_service_t *this)
+{
+ on_accept(this, NULL, NULL, this->prio, this->cncrncy);
+ close(this->fd);
+ this->mutex->destroy(this->mutex);
+ this->condvar->destroy(this->condvar);
+ this->server->destroy(this->server);
+ this->cache->destroy(this->cache);
+ free(this);
+}
+
+/**
+ * See header
+ */
+stream_service_t *tls_stream_service_create_from_fd(int fd,
+ identification_t *server)
+{
+ private_tls_stream_service_t *this;
+
+ INIT(this,
+ .public = {
+ .on_accept = _on_accept,
+ .destroy = _destroy,
+ },
+ .fd = fd,
+ .prio = JOB_PRIO_MEDIUM,
+ .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
+ .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
+ .server = server,
+ .cache = tls_cache_create(25, 180),
+ );
+
+ return &this->public;
+}
+
+/**
+ * See header
+ */
+stream_service_t *tls_stream_service_create(char *uri, int backlog)
+{
+ union {
+ struct sockaddr_in in;
+ struct sockaddr_in6 in6;
+ struct sockaddr sa;
+ } addr;
+ int fd, len, on = 1;
+ identification_t *server;
+
+ len = tls_stream_parse_uri(uri, &addr.sa, &server);
+ 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));
+ server->destroy(server);
+ 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));
+ server->destroy(server);
+ close(fd);
+ return NULL;
+ }
+ if (listen(fd, backlog) < 0)
+ {
+ DBG1(DBG_NET, "listen on socket '%s' failed: %s", uri, strerror(errno));
+ server->destroy(server);
+ close(fd);
+ return NULL;
+ }
+ return tls_stream_service_create_from_fd(fd, server);
+}
--- /dev/null
+/*
+ * 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 tls_stream_service tls_stream_service
+ * @{ @ingroup tls
+ */
+
+#ifndef TLS_STREAM_SERVICE_H_
+#define TLS_STREAM_SERVICE_H_
+
+#include <library.h>
+
+/**
+ * Create a service instance for TLS secured TCP sockets.
+ *
+ * @param uri TLS socket specific URI, must start with "tcp+tls://"
+ * @param backlog size of the backlog queue, as passed to listen()
+ * @return stream_service instance, NULL on failure
+ */
+stream_service_t* tls_stream_service_create(char *uri, int backlog);
+
+#endif /** TLS_STREAM_SERVICE_H_ @}*/