]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
connect: Add simple plugin to initiate/terminate existing connections connect-plugin
authorTobias Brunner <tobias@strongswan.org>
Wed, 18 Feb 2015 11:48:28 +0000 (12:48 +0100)
committerTobias Brunner <tobias@strongswan.org>
Wed, 18 Feb 2015 14:08:23 +0000 (15:08 +0100)
configure.ac
src/libcharon/Makefile.am
src/libcharon/plugins/connect/.gitignore [new file with mode: 0644]
src/libcharon/plugins/connect/Makefile.am [new file with mode: 0644]
src/libcharon/plugins/connect/connect.c [new file with mode: 0644]
src/libcharon/plugins/connect/connect_msg.h [new file with mode: 0644]
src/libcharon/plugins/connect/connect_plugin.c [new file with mode: 0644]
src/libcharon/plugins/connect/connect_plugin.h [new file with mode: 0644]
src/libcharon/plugins/connect/connect_socket.c [new file with mode: 0644]
src/libcharon/plugins/connect/connect_socket.h [new file with mode: 0644]

index f9b235093c7c800680e56be4a2bf80e86cd52181..87f6fa3051f832f279c3bb4f2eace808ea0eea19 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2007-2014 Tobias Brunner
+# Copyright (C) 2007-2015 Tobias Brunner
 # Copyright (C) 2006-2014 Andreas Steffen
 # Copyright (C) 2006-2014 Martin Willi
 # Hochschule fuer Technik Rapperswil
@@ -212,6 +212,7 @@ ARG_DISBL_SET([socket-default], [disable default socket implementation for charo
 ARG_ENABL_SET([socket-dynamic], [enable dynamic socket implementation for charon])
 ARG_ENABL_SET([socket-win],     [enable Winsock2 based socket implementation for charon])
 # configuration/control plugins
+ARG_ENABL_SET([connect],        [simple plugin that allows to initiate/terminate existing connections.])
 ARG_DISBL_SET([stroke],         [disable charons stroke configuration backend.])
 ARG_ENABL_SET([smp],            [enable SMP configuration and control interface. Requires libxml.])
 ARG_ENABL_SET([sql],            [enable SQL database configuration backend.])
@@ -1270,6 +1271,7 @@ ADD_PLUGIN([socket-default],       [c charon nm cmd])
 ADD_PLUGIN([socket-dynamic],       [c charon cmd])
 ADD_PLUGIN([socket-win],           [c charon])
 ADD_PLUGIN([farp],                 [c charon])
+ADD_PLUGIN([connect],              [c charon])
 ADD_PLUGIN([stroke],               [c charon])
 ADD_PLUGIN([vici],                 [c charon])
 ADD_PLUGIN([smp],                  [c charon])
@@ -1404,6 +1406,7 @@ AM_CONDITIONAL(USE_BLISS, test x$bliss = xtrue)
 
 #  charon plugins
 # ----------------
+AM_CONDITIONAL(USE_CONNECT, test x$connect = xtrue)
 AM_CONDITIONAL(USE_STROKE, test x$stroke = xtrue)
 AM_CONDITIONAL(USE_VICI, test x$vici = xtrue)
 AM_CONDITIONAL(USE_MEDSRV, test x$medsrv = xtrue)
@@ -1743,6 +1746,7 @@ AC_CONFIG_FILES([
        src/libcharon/plugins/android_dns/Makefile
        src/libcharon/plugins/android_log/Makefile
        src/libcharon/plugins/maemo/Makefile
+       src/libcharon/plugins/connect/Makefile
        src/libcharon/plugins/stroke/Makefile
        src/libcharon/plugins/vici/Makefile
        src/libcharon/plugins/vici/ruby/Makefile
index e98f5e137698acb13f2dc57873f5ee43a8619826..14b879f7820d10876515c19ad273c782a3c39f83 100644 (file)
@@ -210,6 +210,13 @@ if MONOLITHIC
 endif
 endif
 
+if USE_CONNECT
+  SUBDIRS += plugins/connect
+if MONOLITHIC
+  libcharon_la_LIBADD += plugins/connect/libstrongswan-connect.la
+endif
+endif
+
 if USE_STROKE
   SUBDIRS += plugins/stroke
 if MONOLITHIC
diff --git a/src/libcharon/plugins/connect/.gitignore b/src/libcharon/plugins/connect/.gitignore
new file mode 100644 (file)
index 0000000..1bd5775
--- /dev/null
@@ -0,0 +1 @@
+connect
diff --git a/src/libcharon/plugins/connect/Makefile.am b/src/libcharon/plugins/connect/Makefile.am
new file mode 100644 (file)
index 0000000..b597263
--- /dev/null
@@ -0,0 +1,23 @@
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src/libstrongswan \
+       -I$(top_srcdir)/src/libhydra \
+       -I$(top_srcdir)/src/libcharon \
+       -DIPSEC_PIDDIR=\"${piddir}\"
+
+AM_CFLAGS = \
+       $(PLUGIN_CFLAGS)
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-connect.la
+else
+plugin_LTLIBRARIES = libstrongswan-connect.la
+endif
+
+libstrongswan_connect_la_SOURCES = connect_plugin.h connect_plugin.c \
+       connect_socket.h connect_socket.c connect_msg.h
+
+libstrongswan_connect_la_LDFLAGS = -module -avoid-version
+
+ipsec_PROGRAMS = connect
+connect_SOURCES = connect.c
+connect_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
\ No newline at end of file
diff --git a/src/libcharon/plugins/connect/connect.c b/src/libcharon/plugins/connect/connect.c
new file mode 100644 (file)
index 0000000..a7719c5
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 "connect_msg.h"
+
+#include <arpa/inet.h>
+
+#include <library.h>
+
+/**
+ * Send a message
+ */
+static int send_msg(int type, char *name)
+{
+       connect_msg_t msg = {
+               .type = htonl(type),
+       };
+       stream_t *stream;
+       char *uri, buffer[512];
+       int count;
+
+       uri = lib->settings->get_str(lib->settings, "charon.plugins.connect.socket",
+                                                                "unix://" CONNECT_SOCKET);
+       stream = lib->streams->connect(lib->streams, uri);
+       if (!stream)
+       {
+               fprintf(stderr, "failed to connect to socket '%s'\n", uri);
+               return 2;
+       }
+
+       snprintf(msg.name, sizeof(msg.name), "%s", name);
+       if (!stream->write_all(stream, &msg, sizeof(msg)))
+       {
+               fprintf(stderr, "sending message failed\n");
+               stream->destroy(stream);
+               return 2;
+       }
+
+       while ((count = stream->read(stream, buffer, sizeof(buffer)-1, TRUE)) > 0)
+       {
+               buffer[count] = '\0';
+               printf("%s", buffer);
+       }
+       if (count < 0)
+       {
+               fprintf(stderr, "reading response failed\n");
+       }
+       stream->destroy(stream);
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       library_init(NULL, "connect");
+       atexit(library_deinit);
+
+       if (argc == 3 && strcmp(argv[1], "up") == 0)
+       {
+               return send_msg(CONNECT_INITIATE, argv[2]);
+       }
+       if (argc == 3 && strcmp(argv[1], "down") == 0)
+       {
+               return send_msg(CONNECT_TERMINATE, argv[2]);
+       }
+       fprintf(stderr, "Usage:\n");
+       fprintf(stderr, "  %s up <name>\n", argv[0]);
+       fprintf(stderr, "  %s down <name>\n", argv[0]);
+       return 1;
+}
diff --git a/src/libcharon/plugins/connect/connect_msg.h b/src/libcharon/plugins/connect/connect_msg.h
new file mode 100644 (file)
index 0000000..0bd8d89
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 connect_msg connect_msg
+ * @{ @ingroup connect
+ */
+
+#ifndef CONNECT_MSG_H_
+#define CONNECT_MSG_H_
+
+#define CONNECT_SOCKET IPSEC_PIDDIR "/charon.cnct"
+
+typedef struct connect_msg_t connect_msg_t;
+
+/**
+ * Message type
+ */
+enum {
+       /* initiate a connection */
+       CONNECT_INITIATE = 1,
+       /* terminate a connection */
+       CONNECT_TERMINATE = 2,
+};
+
+/**
+ * Message to exchange over socket
+ */
+struct connect_msg_t {
+       /** message type */
+       int type;
+       /** null terminated connection name */
+       char name[128];
+} __attribute__((packed));
+
+#endif /** CONNECT_MSG_H_ @}*/
diff --git a/src/libcharon/plugins/connect/connect_plugin.c b/src/libcharon/plugins/connect/connect_plugin.c
new file mode 100644 (file)
index 0000000..2c21d84
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 "connect_plugin.h"
+
+#include "connect_socket.h"
+
+#include <daemon.h>
+
+typedef struct private_connect_plugin_t private_connect_plugin_t;
+
+/**
+ * Private data of connect plugin
+ */
+struct private_connect_plugin_t {
+
+       /**
+        * Public interface
+        */
+       connect_plugin_t public;
+
+       /**
+        * Control socket
+        */
+       connect_socket_t *socket;
+};
+
+METHOD(plugin_t, get_name, char*,
+       private_connect_plugin_t *this)
+{
+       return "connect";
+}
+
+/**
+ * Register listener
+ */
+static bool plugin_cb(private_connect_plugin_t *this,
+                                         plugin_feature_t *feature, bool reg, void *cb_data)
+{
+       if (reg)
+       {
+               this->socket = connect_socket_create();
+               return this->socket != NULL;
+       }
+       else
+       {
+               DESTROY_IF(this->socket);
+               return TRUE;
+       }
+}
+
+METHOD(plugin_t, get_features, int,
+       private_connect_plugin_t *this, plugin_feature_t *features[])
+{
+       static plugin_feature_t f[] = {
+               PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
+                       PLUGIN_PROVIDE(CUSTOM, "connect"),
+       };
+       *features = f;
+       return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+       private_connect_plugin_t *this)
+{
+       free(this);
+}
+
+/**
+ * Plugin constructor
+ */
+plugin_t *connect_plugin_create()
+{
+       private_connect_plugin_t *this;
+
+       INIT(this,
+               .public = {
+                       .plugin = {
+                               .get_name = _get_name,
+                               .get_features = _get_features,
+                               .destroy = _destroy,
+                       },
+               },
+       );
+
+       return &this->public.plugin;
+}
diff --git a/src/libcharon/plugins/connect/connect_plugin.h b/src/libcharon/plugins/connect/connect_plugin.h
new file mode 100644 (file)
index 0000000..442ec93
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 connect connect
+ * @ingroup cplugins
+ *
+ * @defgroup connect_plugin connect_plugin
+ * @{ @ingroup connect
+ */
+
+#ifndef CONNECT_PLUGIN_H_
+#define CONNECT_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct connect_plugin_t connect_plugin_t;
+
+/**
+ * Simple plugin to initiate/termiante connections.
+ */
+struct connect_plugin_t {
+
+       /**
+        * Implements plugin interface
+        */
+       plugin_t plugin;
+};
+
+#endif /** CONNECT_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/connect/connect_socket.c b/src/libcharon/plugins/connect/connect_socket.c
new file mode 100644 (file)
index 0000000..1c11c50
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2013-2015 Tobias Brunner
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 "connect_socket.h"
+
+#include <daemon.h>
+#include <collections/array.h>
+
+#include "connect_msg.h"
+
+#define CONNECT_LOG_LEVEL 1
+
+typedef struct private_connect_socket_t private_connect_socket_t;
+
+/**
+ * Private data of a connect_socket_t object
+ */
+struct private_connect_socket_t {
+
+       /**
+        * Public interface
+        */
+       connect_socket_t public;
+
+       /**
+        * Connect stream service
+        */
+       stream_service_t *service;
+};
+
+/**
+ * Logging to the connect socket
+ */
+static bool connect_log(FILE *out, debug_t group, level_t level,
+                                               ike_sa_t *ike_sa, char *message)
+{
+       if (level <= CONNECT_LOG_LEVEL)
+       {
+               if (fprintf(out, "%s", message) < 0 ||
+                       fprintf(out, "\n") < 0 ||
+                       fflush(out) != 0)
+               {
+                       return FALSE;
+               }
+       }
+       return TRUE;
+}
+
+/**
+ * Get the child_cfg with the same name as the peer cfg
+ */
+static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
+{
+       child_cfg_t *current, *found = NULL;
+       enumerator_t *enumerator;
+
+       enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
+       while (enumerator->enumerate(enumerator, &current))
+       {
+               if (streq(current->get_name(current), name))
+               {
+                       found = current;
+                       found->get_ref(found);
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       return found;
+}
+
+/**
+ * Initiate the connection with the given config
+ */
+static void perform_initiate(private_connect_socket_t *this, char *name,
+               peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, FILE *out)
+{
+       status_t status;
+
+       status = charon->controller->initiate(charon->controller, peer_cfg,
+                                                       child_cfg, (controller_cb_t)connect_log, out, 0);
+       switch (status)
+       {
+               case SUCCESS:
+                       fprintf(out, "connection '%s' established successfully\n", name);
+                       break;
+               default:
+               case FAILED:
+                       fprintf(out, "establishing connection '%s' failed\n", name);
+                       break;
+       }
+}
+
+/**
+ * Initiate the connection with the given name
+ */
+static void initiate(private_connect_socket_t *this, char *name, FILE *out)
+{
+       child_cfg_t *child_cfg = NULL;
+       peer_cfg_t *peer_cfg;
+       enumerator_t *enumerator;
+       bool empty = TRUE;
+
+       DBG1(DBG_CFG, "connect: initiate '%s'", name);
+
+       peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, name);
+       if (peer_cfg)
+       {
+               child_cfg = get_child_from_peer(peer_cfg, name);
+               if (child_cfg == NULL)
+               {
+                       enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
+                       while (enumerator->enumerate(enumerator, &child_cfg))
+                       {
+                               empty = FALSE;
+                               perform_initiate(this, name, peer_cfg->get_ref(peer_cfg),
+                                                                child_cfg->get_ref(child_cfg), out);
+                       }
+                       enumerator->destroy(enumerator);
+
+                       if (empty)
+                       {
+                               DBG1(DBG_CFG, "no child config named '%s'", name);
+                               fprintf(out, "no child config named '%s'\n", name);
+                       }
+                       peer_cfg->destroy(peer_cfg);
+                       return;
+               }
+       }
+       else
+       {
+               enumerator = charon->backends->create_peer_cfg_enumerator(
+                                                       charon->backends, NULL, NULL, NULL, NULL, IKE_ANY);
+               while (enumerator->enumerate(enumerator, &peer_cfg))
+               {
+                       child_cfg = get_child_from_peer(peer_cfg, name);
+                       if (child_cfg)
+                       {
+                               peer_cfg->get_ref(peer_cfg);
+                               break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               if (child_cfg == NULL)
+               {
+                       DBG1(DBG_CFG, "no config named '%s'", name);
+                       fprintf(out, "no config named '%s'\n", name);
+                       return;
+               }
+       }
+       perform_initiate(this, name, peer_cfg, child_cfg, out);
+}
+
+/**
+ * Terminate the connection with the given name
+ */
+static void terminate(private_connect_socket_t *this, char *name, FILE *out)
+{
+       ike_sa_t *ike_sa;
+       enumerator_t *enumerator;
+       array_t *ike_sas;
+       status_t status;
+       u_int32_t id, *current;
+
+       DBG1(DBG_CFG, "connect: terminate '%s'", name);
+
+       ike_sas = array_create(sizeof(u_int32_t), 1);
+       enumerator = charon->controller->create_ike_sa_enumerator(
+                                                                                                       charon->controller, TRUE);
+       while (enumerator->enumerate(enumerator, &ike_sa))
+       {
+               if (streq(name, ike_sa->get_name(ike_sa)))
+               {
+                       id = ike_sa->get_unique_id(ike_sa);
+                       array_insert(ike_sas, ARRAY_TAIL, &id);
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       enumerator = array_create_enumerator(ike_sas);
+       while (enumerator->enumerate(enumerator, &current))
+       {
+               status = charon->controller->terminate_ike(charon->controller,
+                                                       *current, (controller_cb_t)connect_log, out, 0);
+               switch (status)
+               {
+                       case SUCCESS:
+                               fprintf(out, "IKE_SA[%d] closed successfully\n", *current);
+                               break;
+                       default:
+                       case FAILED:
+                               fprintf(out, "closing IKE_SA[%d] failed\n", *current);
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (!array_count(ike_sas))
+       {
+               DBG1(DBG_CFG, "no IKE_SA named '%s'", name);
+               fprintf(out, "no IKE_SA named '%s'\n", name);
+       }
+       array_destroy(ike_sas);
+}
+
+/**
+ * Dispatch a received message
+ */
+static bool on_accept(private_connect_socket_t *this, stream_t *stream)
+{
+       connect_msg_t msg;
+       FILE *out;
+
+       if (stream->read_all(stream, &msg, sizeof(msg)))
+       {
+               msg.name[sizeof(msg.name) - 1] = '\0';
+               out = stream->get_file(stream);
+               if (!out)
+               {
+                       DBG1(DBG_CFG, "creating connect output stream failed");
+                       return FALSE;
+               }
+               switch (ntohl(msg.type))
+               {
+                       case CONNECT_INITIATE:
+                               initiate(this, msg.name, out);
+                               break;
+                       case CONNECT_TERMINATE:
+                               terminate(this, msg.name, out);
+                               break;
+                       default:
+                               DBG1(DBG_CFG, "received unknown connect command");
+                               break;
+               }
+               fclose(out);
+       }
+       return FALSE;
+}
+
+METHOD(connect_socket_t, destroy, void,
+       private_connect_socket_t *this)
+{
+       this->service->destroy(this->service);
+       free(this);
+}
+
+/**
+ * See header
+ */
+connect_socket_t *connect_socket_create()
+{
+       private_connect_socket_t *this;
+       char *uri;
+
+       INIT(this,
+               .public = {
+                       .destroy = _destroy,
+               },
+       );
+
+       uri = lib->settings->get_str(lib->settings,
+                                       "%s.plugins.connect.socket", "unix://" CONNECT_SOCKET,
+                                       lib->ns);
+       this->service = lib->streams->create_service(lib->streams, uri, 10);
+       if (!this->service)
+       {
+               DBG1(DBG_CFG, "creating connect socket failed");
+               free(this);
+               return NULL;
+       }
+
+       this->service->on_accept(this->service, (stream_service_cb_t)on_accept,
+                                                        this, JOB_PRIO_CRITICAL, 0);
+
+       return &this->public;
+}
diff --git a/src/libcharon/plugins/connect/connect_socket.h b/src/libcharon/plugins/connect/connect_socket.h
new file mode 100644 (file)
index 0000000..afaa710
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 connect_socket connect_socket
+ * @{ @ingroup connect
+ */
+
+#ifndef CONNECT_SOCKET_H_
+#define CONNECT_SOCKET_H_
+
+typedef struct connect_socket_t connect_socket_t;
+
+/**
+ * Control socket
+ */
+struct connect_socket_t {
+
+       /**
+        * Destroy a connect_socket_t
+        */
+       void (*destroy)(connect_socket_t *this);
+};
+
+/**
+ * Create a connect_socket instance
+ */
+connect_socket_t *connect_socket_create();
+
+#endif /** CONNECT_SOCKET_H_ @}*/