[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r35370 - in gnunet: . src src/gns src/include src/rest
From: |
gnunet |
Subject: |
[GNUnet-SVN] r35370 - in gnunet: . src src/gns src/include src/rest |
Date: |
Wed, 11 Mar 2015 13:54:22 +0100 |
Author: schanzen
Date: 2015-03-11 13:54:22 +0100 (Wed, 11 Mar 2015)
New Revision: 35370
Added:
gnunet/src/gns/plugin_rest_gns.c
gnunet/src/include/gnunet_rest_plugin.h
gnunet/src/rest/
gnunet/src/rest/Makefile.am
gnunet/src/rest/gnunet-rest-server.c
gnunet/src/rest/rest.conf
Modified:
gnunet/configure.ac
gnunet/src/Makefile.am
gnunet/src/gns/Makefile.am
Log:
REST Service
Modified: gnunet/configure.ac
===================================================================
--- gnunet/configure.ac 2015-03-10 12:20:31 UTC (rev 35369)
+++ gnunet/configure.ac 2015-03-11 12:54:22 UTC (rev 35370)
@@ -1216,6 +1216,15 @@
AC_MSG_RESULT($enable_wachs)
AM_CONDITIONAL([HAVE_WACHS], [test "x$enable_wachs" = "xyes"])
+# REST API
+AC_MSG_CHECKING(whether to compile REST API)
+AC_ARG_ENABLE([rest],
+ [AS_HELP_STRING([--enable-rest], [enable REST])],
+ [enable_rest=${enableval}],
+ [enable_rest=no])
+AC_MSG_RESULT($enable_rest)
+AM_CONDITIONAL([HAVE_REST], [test "x$enable_rest" = "xyes"])
+
# should malicious code be compiled (should only be used for testing)?
AC_MSG_CHECKING(whether to compile malicious code)
AC_ARG_ENABLE([malicious],
@@ -1520,6 +1529,7 @@
src/util/resolver.conf
src/vpn/Makefile
src/vpn/vpn.conf
+src/rest/Makefile
pkgconfig/Makefile
pkgconfig/gnunetarm.pc
pkgconfig/gnunetats.pc
Modified: gnunet/src/Makefile.am
===================================================================
--- gnunet/src/Makefile.am 2015-03-10 12:20:31 UTC (rev 35369)
+++ gnunet/src/Makefile.am 2015-03-11 12:54:22 UTC (rev 35370)
@@ -48,6 +48,10 @@
POSTGRES_DIR = postgres
endif
+if HAVE_REST
+ REST_DIR = rest
+endif
+
SUBDIRS = \
include $(INTLEMU_SUBDIRS) \
util \
@@ -60,6 +64,7 @@
peerinfo \
$(MYSQL_DIR) \
$(POSTGRES_DIR) \
+ $(REST_DIR) \
datacache \
datastore \
template \
Modified: gnunet/src/gns/Makefile.am
===================================================================
--- gnunet/src/gns/Makefile.am 2015-03-10 12:20:31 UTC (rev 35369)
+++ gnunet/src/gns/Makefile.am 2015-03-11 12:54:22 UTC (rev 35370)
@@ -85,12 +85,26 @@
endif
endif
+if HAVE_REST
+REST_PLUGIN = libgnunet_plugin_rest_gns.la
+endif
+
bin_SCRIPTS = gnunet-gns-proxy-setup-ca
plugin_LTLIBRARIES = \
libgnunet_plugin_block_gns.la \
- libgnunet_plugin_gnsrecord_gns.la
+ libgnunet_plugin_gnsrecord_gns.la \
+ $(REST_PLUGIN)
+libgnunet_plugin_rest_gns_la_SOURCES = \
+ plugin_rest_gns.c
+libgnunet_plugin_rest_gns_la_LIBADD = \
+ $(top_builddir)/src/gns/libgnunetgns.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
+ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
+ $(LTLIBINTL) -ljansson
+libgnunet_plugin_rest_gns_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
libgnunet_plugin_gnsrecord_gns_la_SOURCES = \
plugin_gnsrecord_gns.c
Added: gnunet/src/gns/plugin_rest_gns.c
===================================================================
--- gnunet/src/gns/plugin_rest_gns.c (rev 0)
+++ gnunet/src/gns/plugin_rest_gns.c 2015-03-11 12:54:22 UTC (rev 35370)
@@ -0,0 +1,658 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2012-2015 Christian Grothoff (and other contributing
authors)
+
+ GNUnet 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 3, or (at your
+ option) any later version.
+
+ GNUnet 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.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @author Martin Schanzenbach
+ * @file gns/plugin_rest_gns.c
+ * @brief GNUnet GNS REST plugin
+ *
+ */
+
+#include "platform.h"
+#include "gnunet_rest_plugin.h"
+#include <gnunet_dnsparser_lib.h>
+#include <gnunet_identity_service.h>
+#include <gnunet_gnsrecord_lib.h>
+#include <gnunet_namestore_service.h>
+#include <gnunet_gns_service.h>
+#include <jansson.h>
+
+#define API_NAMESPACE "gns"
+
+/**
+ * @brief struct returned by the initialization function of the plugin
+ */
+struct Plugin
+{
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+};
+
+const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+struct LookupHandle
+{
+ /**
+ * Handle to GNS service.
+ */
+ struct GNUNET_GNS_Handle *gns;
+
+ /**
+ * Desired timeout for the lookup (default is no timeout).
+ */
+ struct GNUNET_TIME_Relative timeout;
+
+ /**
+ * Handle to lookup request
+ */
+ struct GNUNET_GNS_LookupRequest *lookup_request;
+
+ /**
+ * Lookup an ego with the identity service.
+ */
+ struct GNUNET_IDENTITY_EgoLookup *el;
+
+ /**
+ * Handle for identity service.
+ */
+ struct GNUNET_IDENTITY_Handle *identity;
+
+ /**
+ * Active operation on identity service.
+ */
+ struct GNUNET_IDENTITY_Operation *id_op;
+ /**
+ * ID of a task associated with the resolution process.
+ */
+ struct GNUNET_SCHEDULER_Task * timeout_task;
+
+ json_t *json_root;
+
+ GNUNET_REST_ResultProcessor proc;
+
+ char *name;
+
+ const char *ego_str;
+
+ const char *pkey_str;
+
+ int type;
+
+ struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
+
+ struct GNUNET_CRYPTO_EcdsaPublicKey pkeym;
+
+ enum GNUNET_GNS_LocalOptions options;
+
+ struct GNUNET_CRYPTO_EcdsaPrivateKey shorten_key;
+ void *proc_cls;
+};
+
+void
+cleanup_handle (struct LookupHandle *handle)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Cleaning up\n");
+ if (NULL != handle->json_root)
+ json_decref (handle->json_root);
+
+ if (NULL != handle->name)
+ GNUNET_free (handle->name);
+ if (NULL != handle->el)
+ {
+ GNUNET_IDENTITY_ego_lookup_cancel (handle->el);
+ handle->el = NULL;
+ }
+ if (NULL != handle->id_op)
+ {
+ GNUNET_IDENTITY_cancel (handle->id_op);
+ handle->id_op = NULL;
+ }
+ if (NULL != handle->lookup_request)
+ {
+ GNUNET_GNS_lookup_cancel (handle->lookup_request);
+ handle->lookup_request = NULL;
+ }
+ if (NULL != handle->identity)
+ {
+ GNUNET_IDENTITY_disconnect (handle->identity);
+ handle->identity = NULL;
+ }
+ if (NULL != handle->gns)
+ {
+ GNUNET_GNS_disconnect (handle->gns);
+ handle->gns = NULL;
+ }
+
+ if (NULL != handle->timeout_task)
+ {
+ GNUNET_SCHEDULER_cancel (handle->timeout_task);
+ }
+ GNUNET_free (handle);
+}
+
+
+/**
+ * Task run on shutdown. Cleans up everything.
+ *
+ * @param cls unused
+ * @param tc scheduler context
+ */
+static void
+do_error (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct LookupHandle *handle = cls;
+
+ cleanup_handle (handle);
+ handle->proc (handle->proc_cls, NULL, 0, GNUNET_SYSERR);
+}
+
+/**
+ * Function called with the result of a GNS lookup.
+ *
+ * @param cls the 'const char *' name that was resolved
+ * @param rd_count number of records returned
+ * @param rd array of @a rd_count records with the results
+ */
+static void
+process_lookup_result (void *cls, uint32_t rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "result \n");
+ struct LookupHandle *handle = cls;
+ uint32_t i;
+ const char *typename;
+ char *string_val;
+ char *result;
+ json_t *result_root;
+ json_t *result_name;
+ json_t *result_array;
+ json_t *record_obj;
+
+
+ result_root = json_object();
+ result_name = json_string (handle->name);
+ result_array = json_array();
+ json_object_set (result_root, "name", result_name);
+ json_decref (result_name);
+
+ handle->lookup_request = NULL;
+
+ for (i=0; i<rd_count; i++)
+ {
+ if ( (rd[i].record_type != handle->type) &&
+ (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
+ continue;
+ typename = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
+ string_val = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
+ rd[i].data,
+ rd[i].data_size);
+ if (NULL == string_val)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Record %u of type %d malformed, skipping\n",
+ (unsigned int) i,
+ (int) rd[i].record_type);
+ continue;
+ }
+ else
+ {
+ record_obj = json_object();
+ json_object_set_new (record_obj, "type", json_string (typename));
+ json_object_set_new (record_obj, "value", json_string (string_val));
+ json_array_append (result_array, record_obj);
+ json_decref (record_obj);
+ }
+ GNUNET_free (string_val);
+ }
+ json_object_set (result_root, "query_result", result_array);
+ json_decref (result_array);
+ result = json_dumps (result_root, JSON_COMPACT);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Result %s\n", result);
+ json_decref (result_root);
+ handle->proc (handle->proc_cls, result, strlen (result), GNUNET_OK);
+ GNUNET_free (result);
+ cleanup_handle (handle);
+}
+
+/**
+ * Perform the actual resolution, starting with the zone
+ * identified by the given public key and the shorten zone.
+ *
+ * @param pkey public key to use for the zone, can be NULL
+ * @param shorten_key private key used for shortening, can be NULL
+ */
+static void
+lookup_with_keys (struct LookupHandle *handle, const struct
GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Lookup w/ keys \n");
+ if (UINT32_MAX == handle->type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Invalid typename specified, assuming `ANY'\n"));
+ handle->type = GNUNET_GNSRECORD_TYPE_ANY;
+ }
+
+ if (NULL != handle->name)
+ {
+ handle->lookup_request = GNUNET_GNS_lookup (handle->gns,
+ handle->name,
+ &handle->pkey,
+ handle->type,
+ handle->options,
+ shorten_key,
+ &process_lookup_result,
+ handle);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Please specify name to lookup!\n"));
+ handle->proc (handle->proc_cls, NULL, 0, GNUNET_SYSERR);
+ cleanup_handle (handle);
+ return;
+ }
+}
+
+/**
+ * Method called to with the ego we are to use for shortening
+ * during the lookup.
+ *
+ * @param cls closure contains the public key to use
+ * @param ego ego handle, NULL if not found
+ * @param ctx context for application to store data for this ego
+ * (during the lifetime of this process, initially NULL)
+ * @param name name assigned by the user for this ego,
+ * NULL if the user just deleted the ego and it
+ * must thus no longer be used
+ */
+static void
+identity_shorten_cb (void *cls,
+ struct GNUNET_IDENTITY_Ego *ego,
+ void **ctx,
+ const char *name)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "shorten \n");
+ struct LookupHandle *handle = cls;
+
+ handle->id_op = NULL;
+ if (NULL == ego)
+ lookup_with_keys (handle, NULL);
+ else
+ lookup_with_keys (handle,
+ GNUNET_IDENTITY_ego_get_private_key (ego));
+}
+
+/**
+ * Perform the actual resolution, starting with the zone
+ * identified by the given public key.
+ *
+ * @param pkey public key to use for the zone
+ */
+static void
+lookup_with_public_key (struct LookupHandle *handle)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Lookup w/ pkey \n");
+ handle->pkeym = handle->pkey;
+ GNUNET_break (NULL == handle->id_op);
+ handle->id_op = GNUNET_IDENTITY_get (handle->identity,
+ "gns-short",
+ &identity_shorten_cb,
+ handle);
+ if (NULL == handle->id_op)
+ {
+ GNUNET_break (0);
+ lookup_with_keys (handle, NULL);
+ }
+}
+
+/**
+ * Method called to with the ego we are to use for the lookup,
+ * when the ego is determined by a name.
+ *
+ * @param cls closure (NULL, unused)
+ * @param ego ego handle, NULL if not found
+ */
+static void
+identity_zone_cb (void *cls,
+ const struct GNUNET_IDENTITY_Ego *ego)
+{
+ struct LookupHandle *handle = cls;
+
+ handle->el = NULL;
+ if (NULL == ego)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Ego for not found, cannot perform lookup.\n"));
+ handle->proc (handle->proc_cls, NULL, 0, GNUNET_SYSERR);
+ cleanup_handle (handle);
+ return;
+ }
+ else
+ {
+ GNUNET_IDENTITY_ego_get_public_key (ego, &handle->pkey);
+ lookup_with_public_key (handle);
+ }
+ json_decref(handle->json_root);
+}
+
+/**
+ * Method called to with the ego we are to use for the lookup,
+ * when the ego is the one for the default master zone.
+ *
+ * @param cls closure (NULL, unused)
+ * @param ego ego handle, NULL if not found
+ * @param ctx context for application to store data for this ego
+ * (during the lifetime of this process, initially NULL)
+ * @param name name assigned by the user for this ego,
+ * NULL if the user just deleted the ego and it
+ * must thus no longer be used
+ */
+static void
+identity_master_cb (void *cls,
+ struct GNUNET_IDENTITY_Ego *ego,
+ void **ctx,
+ const char *name)
+{
+ const char *dot;
+ struct LookupHandle *handle = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Master cb \n");
+ handle->id_op = NULL;
+ if (NULL == ego)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Ego for `gns-master' not found, cannot perform lookup. Did you
run gnunet-gns-import.sh?\n"));
+ handle->proc (handle->proc_cls, NULL, 0, GNUNET_SYSERR);
+ cleanup_handle (handle);
+ return;
+ }
+ GNUNET_IDENTITY_ego_get_public_key (ego, &handle->pkey);
+ /* main name is our own master zone, do no look for that in the DHT */
+ handle->options = GNUNET_GNS_LO_LOCAL_MASTER;
+ /* if the name is of the form 'label.gnu', never go to the DHT */
+ dot = NULL;
+ if (NULL != handle->name)
+ dot = strchr (handle->name, '.');
+ if ( (NULL != dot) &&
+ (0 == strcasecmp (dot, ".gnu")) )
+ handle->options = GNUNET_GNS_LO_NO_DHT;
+ lookup_with_public_key (handle);
+}
+
+int
+parse_url (const char *url, struct LookupHandle *handle)
+{
+ char *name;
+ char *type;
+ char tmp_url[strlen(url)+1];
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Parsing %s\n", url);
+ strcpy (tmp_url, url);
+
+ char *tok = strtok ((char*)tmp_url, "/");
+
+
+ if (NULL == tok)
+ return GNUNET_SYSERR;
+
+ name = strtok (NULL, "/");
+
+ if (NULL == name)
+ return GNUNET_SYSERR;
+
+ GNUNET_asprintf (&handle->name,
+ "%s",
+ name);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Got name: %s\n", handle->name);
+
+ type = strtok (NULL, "/");
+
+ if (NULL == type)
+ {
+ handle->type = GNUNET_GNSRECORD_TYPE_ANY;
+ return GNUNET_OK;
+ }
+
+ handle->type = GNUNET_GNSRECORD_typename_to_number (type);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Got type: %s\n", type);
+ return GNUNET_OK;
+}
+
+int
+parse_json (const char *data, size_t data_size, struct LookupHandle *handle)
+{
+ json_error_t error;
+ json_t *pkey_json;
+ json_t *ego_json;
+ json_t *options_json;
+
+ char term_data[data_size+1];
+ term_data[data_size] = '\0';
+
+ memcpy (term_data, data, data_size);
+
+ handle->json_root = json_loads (term_data, 0, &error);
+
+ if (NULL == handle->json_root)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, error.text);
+ return GNUNET_SYSERR;
+ }
+
+ if(!json_is_object(handle->json_root))
+ {
+ return GNUNET_SYSERR;
+ }
+
+ ego_json = json_object_get (handle->json_root, "ego");
+
+ if(json_is_string(ego_json))
+ {
+ handle->ego_str = json_string_value (ego_json);
+ }
+
+ pkey_json = json_object_get (handle->json_root, "pkey");
+ if(json_is_string(pkey_json))
+ {
+ handle->pkey_str = json_string_value (pkey_json);
+ }
+
+ options_json = json_object_get (handle->json_root, "options");
+ if(json_is_integer (options_json))
+ {
+ handle->options = json_integer_value (options_json);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function processing the REST call
+ *
+ * @param method HTTP method
+ * @param url URL of the HTTP request
+ * @param data body of the HTTP request (optional)
+ * @param data_size length of the body
+ * @param proc callback function for the result
+ * @param proc_cls closure for callback function
+ * @return GNUNET_OK if request accepted
+ */
+void
+rest_gns_process_request(const char *method,
+ const char *url,
+ const char *data,
+ size_t data_size,
+ GNUNET_REST_ResultProcessor proc,
+ void *proc_cls)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "In plugin\n");
+ struct LookupHandle *handle = GNUNET_new (struct LookupHandle);
+
+ handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; //TODO read from json
+
+ //parse name and type from url
+ if (GNUNET_OK != parse_url (url, handle))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error parsing url...\n");
+ proc (proc_cls, NULL, 0, GNUNET_SYSERR);
+ cleanup_handle (handle);
+ return;
+ }
+
+ handle->proc_cls = proc_cls;
+ handle->proc = proc;
+
+ if (0 < data_size)
+ {
+ if (GNUNET_OK != parse_json (data, data_size, handle))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error parsing json...\n");
+ proc (proc_cls, NULL, 0, GNUNET_SYSERR);
+ cleanup_handle (handle);
+ return;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Connecting...\n");
+ handle->gns = GNUNET_GNS_connect (cfg);
+ handle->identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
+
+ handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
+ &do_error, handle);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Connected\n");
+
+ if (NULL == handle->gns)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Connecting to GNS failed\n");
+ proc (proc_cls, NULL, 0, GNUNET_SYSERR);
+ cleanup_handle (handle);
+ return;
+ }
+
+ if (NULL != handle->pkey_str)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "pkey_str\n");
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->pkey_str,
+ strlen(handle->pkey_str),
+ &(handle->pkey)))
+ {
+ proc (proc_cls, NULL, 0, GNUNET_SYSERR);
+ cleanup_handle (handle);
+ return;
+ }
+ lookup_with_public_key (handle);
+
+ }
+ if (NULL != handle->ego_str)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "ego_str\n");
+ handle->el = GNUNET_IDENTITY_ego_lookup (cfg,
+ handle->ego_str,
+ &identity_zone_cb,
+ handle);
+ return;
+ }
+ if ( (NULL != handle->name) &&
+ (strlen (handle->name) > 4) &&
+ (0 == strcmp (".zkey",
+ &handle->name[strlen (handle->name) - 4])) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "zkey\n");
+ /* no zone required, use 'anonymous' zone */
+ GNUNET_CRYPTO_ecdsa_key_get_public
+ (GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
+ &(handle->pkey));
+ lookup_with_public_key (handle);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "gns_master\n");
+ GNUNET_break (NULL == handle->id_op);
+ handle->id_op = GNUNET_IDENTITY_get (handle->identity,
+ "gns-master",
+ &identity_master_cb,
+ handle);
+ GNUNET_assert (NULL != handle->id_op);
+ }
+}
+
+/**
+ * Entry point for the plugin.
+ *
+ * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
+ * @return NULL on error, otherwise the plugin context
+ */
+void *
+libgnunet_plugin_rest_gns_init (void *cls)
+{
+ static struct Plugin plugin;
+ cfg = cls;
+ struct GNUNET_REST_Plugin *api;
+
+ if (NULL != plugin.cfg)
+ return NULL; /* can only initialize once! */
+ memset (&plugin, 0, sizeof (struct Plugin));
+ plugin.cfg = cfg;
+ api = GNUNET_new (struct GNUNET_REST_Plugin);
+ api->cls = &plugin;
+ api->name = API_NAMESPACE;
+ api->process_request = &rest_gns_process_request;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("GNS REST API initialized\n"));
+ return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ *
+ * @param cls the plugin context (as returned by "init")
+ * @return always NULL
+ */
+void *
+libgnunet_plugin_namestore_sqlite_done (void *cls)
+{
+ struct GNUNET_REST_Plugin *api = cls;
+ struct Plugin *plugin = api->cls;
+
+ plugin->cfg = NULL;
+ GNUNET_free (api);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "GNS REST plugin is finished\n");
+ return NULL;
+}
+
+/* end of plugin_rest_gns.c */
Added: gnunet/src/include/gnunet_rest_plugin.h
===================================================================
--- gnunet/src/include/gnunet_rest_plugin.h (rev 0)
+++ gnunet/src/include/gnunet_rest_plugin.h 2015-03-11 12:54:22 UTC (rev
35370)
@@ -0,0 +1,100 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2012-2015 Christian Grothoff (and other contributing
authors)
+
+ GNUnet 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 3, or (at your
+ option) any later version.
+
+ GNUnet 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.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @author Martin Schanzenbach
+ * @file include/gnunet_rest_plugin.h
+ * @brief GNUnet service REST plugin header
+ *
+ */
+#ifndef GNUNET_REST_PLUGIN_H
+#define GNUNET_REST_PLUGIN_H
+
+#include "gnunet_util_lib.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+/**
+ * Iterator called on obtained result for a REST result.
+ *
+ * @param cls closure
+ * @param data REST result
+ * @param data_len length of result
+ * @param status status code (HTTP)
+ */
+typedef void (*GNUNET_REST_ResultProcessor) (void *cls,
+ const char *data,
+ size_t data_len,
+ int status);
+
+/**
+ * @brief struct returned by the initialization function of the plugin
+ */
+struct GNUNET_REST_Plugin
+{
+
+ /**
+ *
+ * The closure of the plugin
+ *
+ */
+ void *cls;
+
+ /**
+ * Plugin name. Used as the namespace for the API.
+ * e.g. http://hostname:port/<name>
+ */
+ char *name;
+
+ /**
+ * Function to process a REST call
+ *
+ * @param method the HTTP method called
+ * @param url the relative url accessed
+ * @param data the REST data (can be NULL)
+ * @param data_size the length of the data
+ * @param proc the callback for result
+ * @param proc_cls closure for callback
+ */
+ void (*process_request) (const char *method,
+ const char *url,
+ const char *data,
+ size_t data_size,
+ GNUNET_REST_ResultProcessor proc,
+ void *proc_cls);
+
+};
+
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* end of gnunet_rest_plugin.h */
+#endif
+
Added: gnunet/src/rest/Makefile.am
===================================================================
--- gnunet/src/rest/Makefile.am (rev 0)
+++ gnunet/src/rest/Makefile.am 2015-03-11 12:54:22 UTC (rev 35370)
@@ -0,0 +1,31 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+plugindir = $(libdir)/gnunet
+
+pkgcfgdir= $(pkgdatadir)/config.d/
+
+libexecdir= $(pkglibdir)/libexec/
+
+pkgcfg_DATA = \
+ rest.conf
+
+
+if MINGW
+ WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+endif
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIBS = -lgcov
+endif
+
+libexec_PROGRAMS = \
+ gnunet-rest-server
+
+gnunet_rest_server_SOURCES = \
+ gnunet-rest-server.c
+
+gnunet_rest_server_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL) -lmicrohttpd
Added: gnunet/src/rest/gnunet-rest-server.c
===================================================================
--- gnunet/src/rest/gnunet-rest-server.c (rev 0)
+++ gnunet/src/rest/gnunet-rest-server.c 2015-03-11 12:54:22 UTC (rev
35370)
@@ -0,0 +1,746 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2012-2015 Christian Grothoff (and other contributing
authors)
+
+ GNUnet 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 3, or (at your
+ option) any later version.
+
+ GNUnet 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.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @author Martin Schanzenbach
+ * @file src/rest/gnunet-rest-server.c
+ * @brief REST service for GNUnet services
+ *
+ */
+#include "platform.h"
+#include <microhttpd.h>
+#include "gnunet_util_lib.h"
+#include "gnunet_rest_plugin.h"
+
+
+/**
+ * Default Socks5 listen port.
+ */
+#define GNUNET_REST_SERVICE_PORT 7776
+
+/**
+ * Maximum supported length for a URI.
+ * Should die. @deprecated
+ */
+#define MAX_HTTP_URI_LENGTH 2048
+
+/**
+ * Port for plaintext HTTP.
+ */
+#define HTTP_PORT 80
+
+/**
+ * Port for HTTPS.
+ */
+#define HTTPS_PORT 443
+
+/**
+ * After how long do we clean up unused MHD SSL/TLS instances?
+ */
+#define MHD_CACHE_TIMEOUT GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_MINUTES, 5)
+
+#define GN_REST_STATE_INIT 0
+#define GN_REST_STATE_UPLOAD 1
+#define GN_REST_STATE_RECV 2
+
+/**
+ * The task ID
+ */
+struct GNUNET_SCHEDULER_Task * httpd_task;
+
+/**
+ * is this an ssl daemon? //TODO
+ */
+int is_ssl;
+
+/**
+ * The port the service is running on (default 7776)
+ */
+static unsigned long port = GNUNET_REST_SERVICE_PORT;
+
+/**
+ * The listen socket of the service for IPv4
+ */
+static struct GNUNET_NETWORK_Handle *lsock4;
+
+/**
+ * The listen socket of the service for IPv6
+ */
+static struct GNUNET_NETWORK_Handle *lsock6;
+
+/**
+ * The listen task ID for IPv4
+ */
+static struct GNUNET_SCHEDULER_Task * ltask4;
+
+/**
+ * The listen task ID for IPv6
+ */
+static struct GNUNET_SCHEDULER_Task * ltask6;
+
+/**
+ * Daemon for HTTP
+ */
+static struct MHD_Daemon *httpd;
+
+/**
+ * Response we return on failures.
+ */
+static struct MHD_Response *failure_response;
+
+/**
+ * Our configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Map of loaded plugins.
+ */
+struct GNUNET_CONTAINER_MultiHashMap *plugin_map;
+
+/**
+ * MHD Connection handle
+ */
+struct MhdConnectionHandle
+{
+ struct MHD_Connection *con;
+
+ struct MHD_Response *response;
+
+ struct GNUNET_REST_Plugin *plugin;
+
+ int status;
+
+ int state;
+};
+
+/* ************************* Global helpers ********************* */
+
+
+/**
+ * Task run whenever HTTP server operations are pending.
+ *
+ * @param cls NULL
+ * @param tc sched context
+ */
+static void
+do_httpd (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Run MHD now, we have extra data ready for the callback.
+ *
+ * @param hd the daemon to run now.
+ */
+static void
+run_mhd_now ()
+{
+ if (NULL !=
+ httpd_task)
+ GNUNET_SCHEDULER_cancel (httpd_task);
+ httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd,
+ NULL);
+}
+
+/**
+ * Plugin result callback
+ *
+ * @param cls closure (MHD connection handle)
+ * @param data the data to return to the caller
+ * @param len length of the data
+ * @param status GNUNET_OK if successful
+ */
+void
+plugin_callback (void *cls,
+ const char *data,
+ size_t len,
+ int status)
+{
+ struct MhdConnectionHandle *handle = cls;
+ struct MHD_Response *resp = MHD_create_response_from_buffer (len,
+ (void*)data,
+
MHD_RESPMEM_MUST_COPY);
+ (void) MHD_add_response_header
(resp,MHD_HTTP_HEADER_CONTENT_TYPE,"application/json");
+ handle->status = status;
+ handle->response = resp;
+ run_mhd_now();
+}
+
+/* ********************************* MHD response generation
******************* */
+
+/**
+ * Main MHD callback for handling requests.
+ *
+ * @param cls unused
+ * @param con MHD connection handle
+ * @param url the url in the request
+ * @param meth the HTTP method used ("GET", "PUT", etc.)
+ * @param ver the HTTP version string (i.e. "HTTP/1.1")
+ * @param upload_data the data being uploaded (excluding HEADERS,
+ * for a POST that fits into memory and that is encoded
+ * with a supported encoding, the POST data will NOT be
+ * given in upload_data and is instead available as
+ * part of MHD_get_connection_values; very large POST
+ * data *will* be made available incrementally in
+ * upload_data)
+ * @param upload_data_size set initially to the size of the
+ * @a upload_data provided; the method must update this
+ * value to the number of bytes NOT processed;
+ * @param con_cls pointer to location where we store the 'struct Request'
+ * @return MHD_YES if the connection was handled successfully,
+ * MHD_NO if the socket must be closed due to a serious
+ * error while handling the request
+ */
+static int
+create_response (void *cls,
+ struct MHD_Connection *con,
+ const char *url,
+ const char *meth,
+ const char *ver,
+ const char *upload_data,
+ size_t *upload_data_size,
+ void **con_cls)
+{
+ char *plugin_name;
+ struct GNUNET_HashCode key;
+ struct MhdConnectionHandle *con_handle;
+
+ con_handle = *con_cls;
+
+ if (NULL == *con_cls)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "New connection %s\n", url);
+ char tmp_url[strlen(url)+1];
+ strcpy (tmp_url, url);
+ con_handle = GNUNET_new (struct MhdConnectionHandle);
+ con_handle->con = con;
+ con_handle->state = GN_REST_STATE_INIT;
+ *con_cls = con_handle;
+
+ plugin_name = strtok(tmp_url, "/");
+
+ if (NULL != plugin_name)
+ {
+ GNUNET_CRYPTO_hash (plugin_name, strlen (plugin_name), &key);
+
+ con_handle->plugin = GNUNET_CONTAINER_multihashmap_get (plugin_map,
+ &key);
+ }
+ else
+ con_handle->plugin = NULL;
+
+ if (NULL == con_handle->plugin)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Queueing response with MHD\n");
+ GNUNET_free (con_handle);
+ MHD_queue_response (con,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ failure_response);
+ }
+ return MHD_YES;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Size %d\n", *upload_data_size);
+ if (GN_REST_STATE_INIT == con_handle->state)
+ {
+ if (0 != *upload_data_size)
+ {
+ con_handle->state = GN_REST_STATE_UPLOAD;
+
+ con_handle->plugin->process_request (meth,
+ url,
+ upload_data,
+ *upload_data_size,
+ &plugin_callback,
+ con_handle);
+ *upload_data_size = 0;
+
+ }
+ else
+ {
+ con_handle->state = GN_REST_STATE_RECV;
+ con_handle->plugin->process_request (meth,
+ url,
+ NULL,
+ 0,
+ &plugin_callback,
+ con_handle);
+ }
+ }
+ if (NULL != con_handle->response)
+ {
+
+GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Queueing response from plugin with MHD\n");
+ if (GNUNET_OK == con_handle->status) {
+ return MHD_queue_response (con,
+ MHD_HTTP_OK,
+ con_handle->response);
+ } else {
+ return MHD_queue_response (con,
+ MHD_HTTP_BAD_REQUEST,
+ con_handle->response);
+ }
+ }
+ return MHD_YES;
+}
+
+/* ******************** MHD HTTP setup and event loop ******************** */
+
+/**
+ * Function called when MHD decides that we are done with a connection.
+ *
+ * @param cls NULL
+ * @param connection connection handle
+ * @param con_cls value as set by the last call to
+ * the MHD_AccessHandlerCallback, should be our handle
+ * @param toe reason for request termination (ignored)
+ */
+static void
+mhd_completed_cb (void *cls,
+ struct MHD_Connection *connection,
+ void **con_cls,
+ enum MHD_RequestTerminationCode toe)
+{
+
+ if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "MHD encountered error handling request: %d\n",
+ toe);
+ *con_cls = NULL;
+}
+
+/**
+ * Kill the MHD daemon.
+ */
+static void
+kill_httpd ()
+{
+ MHD_stop_daemon (httpd);
+ if (NULL != httpd_task)
+ {
+ GNUNET_SCHEDULER_cancel (httpd_task);
+ httpd_task = NULL;
+ }
+}
+
+/**
+ * Task run whenever HTTP server is idle for too long. Kill it.
+ *
+ * @param cls NULL
+ * @param tc sched context
+ */
+static void
+kill_httpd_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ httpd_task = NULL;
+ kill_httpd ();
+}
+/**
+ * Schedule MHD. This function should be called initially when an
+ * MHD is first getting its client socket, and will then automatically
+ * always be called later whenever there is work to be done.
+ *
+ * @param hd the daemon to schedule
+ */
+static void
+schedule_httpd ()
+{
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ struct GNUNET_NETWORK_FDSet *wrs;
+ struct GNUNET_NETWORK_FDSet *wws;
+ int max;
+ int haveto;
+ MHD_UNSIGNED_LONG_LONG timeout;
+ struct GNUNET_TIME_Relative tv;
+
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ max = -1;
+ if (MHD_YES != MHD_get_fdset (httpd, &rs, &ws, &es, &max))
+ {
+ kill_httpd ();
+ return;
+ }
+ haveto = MHD_get_timeout (httpd, &timeout);
+ if (MHD_YES == haveto)
+ tv.rel_value_us = (uint64_t) timeout * 1000LL;
+ else
+ tv = GNUNET_TIME_UNIT_FOREVER_REL;
+ if (-1 != max)
+ {
+ wrs = GNUNET_NETWORK_fdset_create ();
+ wws = GNUNET_NETWORK_fdset_create ();
+ GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
+ GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
+ }
+ else
+ {
+ wrs = NULL;
+ wws = NULL;
+ }
+ if (NULL != httpd_task)
+ GNUNET_SCHEDULER_cancel (httpd_task);
+ if ( (MHD_YES != haveto) &&
+ (-1 == max))
+ {
+ /* daemon is idle, kill after timeout */
+ httpd_task = GNUNET_SCHEDULER_add_delayed (MHD_CACHE_TIMEOUT,
+ &kill_httpd_task,
+ NULL);
+ }
+ else
+ {
+ httpd_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ tv, wrs, wws,
+ &do_httpd, NULL);
+ }
+ if (NULL != wrs)
+ GNUNET_NETWORK_fdset_destroy (wrs);
+ if (NULL != wws)
+ GNUNET_NETWORK_fdset_destroy (wws);
+}
+
+/**
+ * Task run whenever HTTP server operations are pending.
+ *
+ * @param cls NULL
+ * @param tc scheduler context
+ */
+static void
+do_httpd (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ httpd_task = NULL;
+ MHD_run (httpd);
+ schedule_httpd ();
+}
+
+/**
+ * Accept new incoming connections
+ *
+ * @param cls the closure with the lsock4 or lsock6
+ * @param tc the scheduler context
+ */
+static void
+do_accept (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_NETWORK_Handle *lsock = cls;
+ struct GNUNET_NETWORK_Handle *s;
+ int fd;
+ const struct sockaddr *addr;
+ socklen_t len;
+
+ if (lsock == lsock4)
+ ltask4 = NULL;
+ else
+ ltask6 = NULL;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ if (lsock == lsock4)
+ ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+ lsock,
+ &do_accept, lsock);
+ else
+ ltask6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+ lsock,
+ &do_accept, lsock);
+ s = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
+ if (NULL == s)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "accept");
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got an inbound connection, waiting for data\n");
+ fd = GNUNET_NETWORK_get_fd (s);
+ addr = GNUNET_NETWORK_get_addr (s);
+ len = GNUNET_NETWORK_get_addrlen (s);
+ if (MHD_YES != MHD_add_connection (httpd, fd, addr, len))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Failed to pass client to MHD\n"));
+ return;
+ }
+
+ schedule_httpd ();
+}
+
+/**
+ * Task run on shutdown
+ *
+ * @param cls closure
+ * @param tc task context
+ */
+static void
+do_shutdown (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Shutting down...\n");
+ kill_httpd ();
+}
+
+/**
+ * Create an IPv4 listen socket bound to our port.
+ *
+ * @return NULL on error
+ */
+static struct GNUNET_NETWORK_Handle *
+bind_v4 ()
+{
+ struct GNUNET_NETWORK_Handle *ls;
+ struct sockaddr_in sa4;
+ int eno;
+
+ memset (&sa4, 0, sizeof (sa4));
+ sa4.sin_family = AF_INET;
+ sa4.sin_port = htons (port);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ sa4.sin_len = sizeof (sa4);
+#endif
+ ls = GNUNET_NETWORK_socket_create (AF_INET,
+ SOCK_STREAM,
+ 0);
+ if (NULL == ls)
+ return NULL;
+ if (GNUNET_OK !=
+ GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa4,
+ sizeof (sa4)))
+ {
+ eno = errno;
+ GNUNET_NETWORK_socket_close (ls);
+ errno = eno;
+ return NULL;
+ }
+ return ls;
+}
+
+/**
+ * Create an IPv6 listen socket bound to our port.
+ *
+ * @return NULL on error
+ */
+static struct GNUNET_NETWORK_Handle *
+bind_v6 ()
+{
+ struct GNUNET_NETWORK_Handle *ls;
+ struct sockaddr_in6 sa6;
+ int eno;
+
+ memset (&sa6, 0, sizeof (sa6));
+ sa6.sin6_family = AF_INET6;
+ sa6.sin6_port = htons (port);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ sa6.sin6_len = sizeof (sa6);
+#endif
+ ls = GNUNET_NETWORK_socket_create (AF_INET6,
+ SOCK_STREAM,
+ 0);
+ if (NULL == ls)
+ return NULL;
+ if (GNUNET_OK !=
+ GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa6,
+ sizeof (sa6)))
+ {
+ eno = errno;
+ GNUNET_NETWORK_socket_close (ls);
+ errno = eno;
+ return NULL;
+ }
+ return ls;
+}
+
+/**
+ * Callback for plugin load
+ *
+ * @param cls NULL
+ * @param libname the name of the library loaded
+ * @param lib_ret the object returned by the plugin initializer
+ */
+void
+load_plugin (void *cls,
+ const char *libname,
+ void *lib_ret)
+{
+ struct GNUNET_REST_Plugin *plugin = lib_ret;
+ struct GNUNET_HashCode key;
+ if (NULL == lib_ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not load plugin `%s'\n",
+ libname);
+ return;
+ }
+
+ GNUNET_CRYPTO_hash (plugin->name, strlen (plugin->name), &key);
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (plugin_map,
+ &key,
+ plugin,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not load add plugin `%s'\n",
+ libname);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Loaded plugin `%s'\n",
+ libname);
+}
+
+/**
+ * Main function that will be run
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL)
+ * @param c configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ cfg = c;
+
+ plugin_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
+
+ /* Load plugins */
+ GNUNET_PLUGIN_load_all ("libgnunet_plugin_rest",
+ (void *) cfg,
+ &load_plugin,
+ NULL);
+
+
+ /* Open listen socket proxy */
+ lsock6 = bind_v6 ();
+ if (NULL == lsock6)
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
+ else
+ {
+ if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock6, 5))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
+ GNUNET_NETWORK_socket_close (lsock6);
+ lsock6 = NULL;
+ }
+ else
+ {
+ ltask6 = GNUNET_SCHEDULER_add_read_net
(GNUNET_TIME_UNIT_FOREVER_REL,
+ lsock6, &do_accept,
lsock6);
+ }
+ }
+ lsock4 = bind_v4 ();
+ if (NULL == lsock4)
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
+ else
+ {
+ if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock4, 5))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
+ GNUNET_NETWORK_socket_close (lsock4);
+ lsock4 = NULL;
+ }
+ else
+ {
+ ltask4 = GNUNET_SCHEDULER_add_read_net
(GNUNET_TIME_UNIT_FOREVER_REL,
+ lsock4, &do_accept,
lsock4);
+ }
+ }
+ if ( (NULL == lsock4) &&
+ (NULL == lsock6) )
+ {
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Service listens on port %u\n",
+ port);
+ httpd = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET,
+ 0,
+ NULL, NULL,
+ &create_response, NULL,
+ MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
int) 16,
+ MHD_OPTION_NOTIFY_COMPLETED,
&mhd_completed_cb, NULL,
+ MHD_OPTION_END);
+ if (NULL == httpd)
+ {
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+
+
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &do_shutdown, NULL);
+}
+
+/**
+ *
+ * The main function for gnunet-rest-service
+ *
+ * @param argc number of arguments from the cli
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ *
+ */
+int
+main (int argc, char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'p', "port", NULL,
+ gettext_noop ("listen on specified port (default: 7776)"), 1,
+ &GNUNET_GETOPT_set_ulong, &port},
+ GNUNET_GETOPT_OPTION_END
+ };
+ static const char* err_page =
+ "<html><head><title>gnunet-rest-service</title>"
+ "</head><body>ERROR</body></html>";
+ int ret;
+
+ if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+ return 2;
+ GNUNET_log_setup ("gnunet-rest-service", "WARNING", NULL);
+ failure_response = MHD_create_response_from_buffer (strlen(err_page),
+ (void*)err_page,
+
MHD_RESPMEM_PERSISTENT);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Start\n");
+ ret =
+ (GNUNET_OK ==
+ GNUNET_PROGRAM_run (argc, argv, "gnunet-rest-service",
+ _("GNUnet REST service"),
+ options,
+ &run, NULL)) ? 0: 1;
+ MHD_destroy_response (failure_response);
+ GNUNET_free_non_null ((char *) argv);
+ return ret;
+}
+
+/* end of gnunet-rest-service.c */
Added: gnunet/src/rest/rest.conf
===================================================================
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r35370 - in gnunet: . src src/gns src/include src/rest,
gnunet <=