[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r38186 - in gnunet/src: include util
From: |
gnunet |
Subject: |
[GNUnet-SVN] r38186 - in gnunet/src: include util |
Date: |
Sun, 23 Oct 2016 18:03:55 +0200 |
Author: grothoff
Date: 2016-10-23 18:03:54 +0200 (Sun, 23 Oct 2016)
New Revision: 38186
Added:
gnunet/src/util/service.c
Removed:
gnunet/src/util/client.c
gnunet/src/util/service.c
Modified:
gnunet/src/include/gnunet_client_lib.h
gnunet/src/util/Makefile.am
gnunet/src/util/mq.c
Log:
move to new client API: remove old client API
Modified: gnunet/src/include/gnunet_client_lib.h
===================================================================
--- gnunet/src/include/gnunet_client_lib.h 2016-10-23 16:03:36 UTC (rev
38185)
+++ gnunet/src/include/gnunet_client_lib.h 2016-10-23 16:03:54 UTC (rev
38186)
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2001-2013 GNUnet e.V.
+ Copyright (C) 2001-2013, 2016 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -45,12 +45,7 @@
#include "gnunet_mq_lib.h"
-/**
- * Opaque handle for a connection to a service.
- */
-struct GNUNET_CLIENT_Connection;
-
/**
* Create a message queue to connect to a GNUnet service.
* If handlers are specfied, receive messages from the connection.
@@ -69,209 +64,6 @@
void *error_handler_cls);
-/**
- * Create a message queue for a GNUNET_CLIENT_Connection.
- * If handlers are specfied, receive messages from the connection.
- *
- * @param connection the client connection, taken over and freed by the MQ
- * @param handlers handlers for receiving messages
- * @param error_handler error handler
- * @param error_handler_cls closure for the @a error_handler
- * @return the message queue
- * @deprecated use #GNUNET_CLIENT_connecT
- */
-struct GNUNET_MQ_Handle *
-GNUNET_MQ_queue_for_connection_client (struct GNUNET_CLIENT_Connection
*connection,
- const struct GNUNET_MQ_MessageHandler
*handlers,
- GNUNET_MQ_ErrorHandler error_handler,
- void *error_handler_cls);
-
-
-/**
- * Get a connection with a service.
- *
- * @param service_name name of the service
- * @param cfg configuration to use
- * @return NULL on error (service unknown to configuration)
- * @deprecated use #GNUNET_CLIENT_connect2
- */
-struct GNUNET_CLIENT_Connection *
-GNUNET_CLIENT_connect (const char *service_name,
- const struct GNUNET_CONFIGURATION_Handle *cfg);
-
-
-/**
- * Destroy connection with the service. This will automatically
- * cancel any pending "receive" request (however, the handler will
- * *NOT* be called, not even with a NULL message). Any pending
- * transmission request will also be cancelled UNLESS the callback for
- * the transmission request has already been called, in which case the
- * transmission 'finish_pending_write' argument determines whether or
- * not the write is guaranteed to complete before the socket is fully
- * destroyed (unless, of course, there is an error with the server in
- * which case the message may still be lost).
- *
- * @param client handle to the service connection
- * @deprecated
- */
-void
-GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *client);
-
-
-/**
- * Type of a function to call when we receive a message
- * from the service.
- *
- * @param cls closure
- * @param msg message received, NULL on timeout or fatal error
- */
-typedef void
-(*GNUNET_CLIENT_MessageHandler) (void *cls,
- const struct GNUNET_MessageHeader *msg);
-
-
-/**
- * Read from the service.
- *
- * @param client connection to the service
- * @param handler function to call with the message
- * @param handler_cls closure for @a handler
- * @param timeout how long to wait until timing out
- * @deprecated
- */
-void
-GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *client,
- GNUNET_CLIENT_MessageHandler handler,
- void *handler_cls,
- struct GNUNET_TIME_Relative timeout);
-
-
-/**
- * Transmit handle for client connections.
- */
-struct GNUNET_CLIENT_TransmitHandle;
-
-
-/**
- * Ask the client to call us once the specified number of bytes
- * are free in the transmission buffer. Will never call the @a notify
- * callback in this task, but always first go into the scheduler.
- *
- * @param client connection to the service
- * @param size number of bytes to send
- * @param timeout after how long should we give up (and call
- * @a notify with buf NULL and size 0)?
- * @param auto_retry if the connection to the service dies, should we
- * automatically re-connect and retry (within the timeout period)
- * or should we immediately fail in this case? Pass #GNUNET_YES
- * if the caller does not care about temporary connection errors,
- * for example because the protocol is stateless
- * @param notify function to call
- * @param notify_cls closure for @a notify
- * @return NULL if someone else is already waiting to be notified
- * non-NULL if the notify callback was queued (can be used to cancel
- * using #GNUNET_CONNECTION_notify_transmit_ready_cancel)
- * @deprecated
- */
-struct GNUNET_CLIENT_TransmitHandle *
-GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client,
- size_t size,
- struct GNUNET_TIME_Relative timeout,
- int auto_retry,
- GNUNET_CONNECTION_TransmitReadyNotify
notify,
- void *notify_cls);
-
-
-/**
- * Cancel a request for notification.
- *
- * @param th handle from the original request.
- * @deprecated
- */
-void
-GNUNET_CLIENT_notify_transmit_ready_cancel (struct
GNUNET_CLIENT_TransmitHandle *th);
-
-
-/**
- * Convenience API that combines sending a request
- * to the service and waiting for a response.
- * If either operation times out, the callback
- * will be called with a "NULL" response (in which
- * case the connection should probably be destroyed).
- *
- * @param client connection to use
- * @param hdr message to transmit
- * @param timeout when to give up (for both transmission
- * and for waiting for a response)
- * @param auto_retry if the connection to the service dies, should we
- * automatically re-connect and retry (within the timeout period)
- * or should we immediately fail in this case? Pass #GNUNET_YES
- * if the caller does not care about temporary connection errors,
- * for example because the protocol is stateless
- * @param rn function to call with the response
- * @param rn_cls closure for @a rn
- * @return #GNUNET_OK on success, #GNUNET_SYSERR if a request
- * is already pending
- * @deprecated
- */
-int
-GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection
*client,
- const struct GNUNET_MessageHeader
*hdr,
- struct GNUNET_TIME_Relative timeout,
- int auto_retry,
- GNUNET_CLIENT_MessageHandler rn,
- void *rn_cls);
-
-
-/**
- * Handle for a test to check if a service is running.
- */
-struct GNUNET_CLIENT_TestHandle;
-
-/**
- * Function called with the result on the service test.
- *
- * @param cls closure
- * @param result #GNUNET_YES if the service is running,
- * #GNUNET_NO if the service is not running
- * #GNUNET_SYSERR if the configuration is invalid
- */
-typedef void
-(*GNUNET_CLIENT_TestResultCallback)(void *cls,
- int result);
-
-
-/**
- * Test if the service is running. If we are given a UNIXPATH or a
- * local address, we do this NOT by trying to connect to the service,
- * but by trying to BIND to the same port. If the BIND fails, we know
- * the service is running.
- *
- * @param service name of the service to wait for
- * @param cfg configuration to use
- * @param timeout how long to wait at most
- * @param cb function to call with the result
- * @param cb_cls closure for @a cb
- * @return handle to cancel the test
- * @deprecated
- */
-struct GNUNET_CLIENT_TestHandle *
-GNUNET_CLIENT_service_test (const char *service,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_CLIENT_TestResultCallback cb, void *cb_cls);
-
-
-/**
- * Abort testing for service.
- *
- * @param th test handle
- * @deprecated
- */
-void
-GNUNET_CLIENT_service_test_cancel (struct GNUNET_CLIENT_TestHandle *th);
-
-
#if 0 /* keep Emacsens' auto-indent happy */
{
#endif
Modified: gnunet/src/util/Makefile.am
===================================================================
--- gnunet/src/util/Makefile.am 2016-10-23 16:03:36 UTC (rev 38185)
+++ gnunet/src/util/Makefile.am 2016-10-23 16:03:54 UTC (rev 38186)
@@ -59,7 +59,6 @@
libgnunetutil_la_SOURCES = \
bandwidth.c \
bio.c \
- client.c \
client_new.c \
common_allocation.c \
common_endian.c \
Deleted: gnunet/src/util/client.c
===================================================================
--- gnunet/src/util/client.c 2016-10-23 16:03:36 UTC (rev 38185)
+++ gnunet/src/util/client.c 2016-10-23 16:03:54 UTC (rev 38186)
@@ -1,1299 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2001-2013 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/client.c
- * @brief code for access to services
- * @author Christian Grothoff
- *
- * Generic TCP code for reliable, record-oriented TCP
- * connections between clients and service providers.
- */
-#include "platform.h"
-#include "gnunet_protocols.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_socks.h"
-
-
-/**
- * How often do we re-try tranmsitting requests before giving up?
- * Note that if we succeeded transmitting a request but failed to read
- * a response, we do NOT re-try.
- */
-#define MAX_ATTEMPTS 50
-
-#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__)
-
-/**
- * Handle for a transmission request.
- */
-struct GNUNET_CLIENT_TransmitHandle
-{
- /**
- * Connection state.
- */
- struct GNUNET_CLIENT_Connection *client;
-
- /**
- * Function to call to get the data for transmission.
- */
- GNUNET_CONNECTION_TransmitReadyNotify notify;
-
- /**
- * Closure for @e notify.
- */
- void *notify_cls;
-
- /**
- * Handle to the transmission with the underlying
- * connection.
- */
- struct GNUNET_CONNECTION_TransmitHandle *th;
-
- /**
- * If we are re-trying and are delaying to do so,
- * handle to the scheduled task managing the delay.
- */
- struct GNUNET_SCHEDULER_Task *reconnect_task;
-
- /**
- * Timeout for the operation overall.
- */
- struct GNUNET_TIME_Absolute timeout;
-
- /**
- * Number of bytes requested.
- */
- size_t size;
-
- /**
- * Are we allowed to re-try to connect without telling
- * the user (of this API) about the connection troubles?
- */
- int auto_retry;
-
- /**
- * Number of attempts left for transmitting the request. We may
- * fail the first time (say because the service is not yet up), in
- * which case (if auto_retry is set) we wait a bit and re-try
- * (timeout permitting).
- */
- unsigned int attempts_left;
-
-};
-
-
-/**
- * Struct to refer to a GNUnet TCP connection.
- * This is more than just a socket because if the server
- * drops the connection, the client automatically tries
- * to reconnect (and for that needs connection information).
- */
-struct GNUNET_CLIENT_Connection
-{
-
- /**
- * The connection handle, NULL if not live
- */
- struct GNUNET_CONNECTION_Handle *connection;
-
- /**
- * Our configuration.
- */
- const struct GNUNET_CONFIGURATION_Handle *cfg;
-
- /**
- * Name of the service we interact with.
- */
- char *service_name;
-
- /**
- * Handler for current receiver task.
- */
- GNUNET_CLIENT_MessageHandler receiver_handler;
-
- /**
- * Closure for @e receiver_handler.
- */
- void *receiver_handler_cls;
-
- /**
- * Handle for a pending transmission request, NULL if there is
- * none pending.
- */
- struct GNUNET_CLIENT_TransmitHandle *th;
-
- /**
- * If we are re-trying and are delaying to do so,
- * handle to the scheduled task managing the delay.
- */
- struct GNUNET_SCHEDULER_Task * receive_task;
-
- /**
- * Buffer for received message.
- */
- char *received_buf;
-
- /**
- * Timeout for receiving a response (absolute time).
- */
- struct GNUNET_TIME_Absolute receive_timeout;
-
- /**
- * Current value for our incremental back-off (for
- * connect re-tries).
- */
- struct GNUNET_TIME_Relative back_off;
-
- /**
- * Number of bytes in received_buf that are valid.
- */
- size_t received_pos;
-
- /**
- * Size of received_buf.
- */
- unsigned int received_size;
-
- /**
- * Do we have a complete response in received_buf?
- */
- int msg_complete;
-
- /**
- * Are we currently busy doing receive-processing?
- * #GNUNET_YES if so, #GNUNET_NO if not. #GNUNET_SYSERR
- * if the connection has failed (but we may not have
- * closed the handle itself yet).
- */
- int in_receive;
-
- /**
- * Is this the first message we are sending to the service?
- */
- int first_message;
-
- /**
- * How often have we tried to connect?
- */
- unsigned int attempts;
-
-};
-
-
-/**
- * Try connecting to the server using UNIX domain sockets.
- *
- * @param service_name name of service to connect to
- * @param cfg configuration to use
- * @return NULL on error, connection to UNIX otherwise
- */
-static struct GNUNET_CONNECTION_Handle *
-try_unixpath (const char *service_name,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
-#if AF_UNIX
- struct GNUNET_CONNECTION_Handle *connection;
- char *unixpath;
- struct sockaddr_un s_un;
-
- unixpath = NULL;
- if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
service_name, "UNIXPATH", &unixpath)) &&
- (0 < strlen (unixpath)))
- {
- /* We have a non-NULL unixpath, need to validate it */
- if (strlen (unixpath) >= sizeof (s_un.sun_path))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
- (unsigned long long) sizeof (s_un.sun_path));
- unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Using `%s' instead\n"), unixpath);
- if (NULL == unixpath)
- return NULL;
- }
- connection = GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg,
unixpath);
- if (NULL != connection)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Connected to unixpath `%s'!\n",
- unixpath);
- GNUNET_free (unixpath);
- return connection;
- }
- }
- GNUNET_free_non_null (unixpath);
-#endif
- return NULL;
-}
-
-
-/**
- * Test whether the configuration has proper values for connection
- * (UNIXPATH || (PORT && HOSTNAME)).
- *
- * @param service_name name of service to connect to
- * @param cfg configuration to use
- * @return #GNUNET_OK if the configuration is valid, #GNUNET_SYSERR if not
- */
-static int
-test_service_configuration (const char *service_name,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- int ret = GNUNET_SYSERR;
- char *hostname = NULL;
- unsigned long long port;
-#if AF_UNIX
- char *unixpath = NULL;
-
- if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
service_name, "UNIXPATH", &unixpath)) &&
- (0 < strlen (unixpath)))
- ret = GNUNET_OK;
- GNUNET_free_non_null (unixpath);
-#endif
-
- if ( (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) &&
- (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT",
&port)) &&
- (port <= 65535) && (0 != port) &&
- (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME",
- &hostname)) &&
- (0 != strlen (hostname)) )
- ret = GNUNET_OK;
- GNUNET_free_non_null (hostname);
- return ret;
-}
-
-
-/**
- * Try to connect to the service.
- *
- * @param service_name name of service to connect to
- * @param cfg configuration to use
- * @param attempt counter used to alternate between IP and UNIX domain sockets
- * @return NULL on error
- */
-static struct GNUNET_CONNECTION_Handle *
-do_connect (const char *service_name,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- unsigned int attempt)
-{
- struct GNUNET_CONNECTION_Handle *connection;
- char *hostname;
- unsigned long long port;
-
- /* Never use a local source if a proxy is configured */
- if (GNUNET_YES == GNUNET_SOCKS_check_service (service_name,cfg))
- return GNUNET_SOCKS_do_connect (service_name,cfg);
-
- connection = NULL;
- if (0 == (attempt % 2))
- {
- /* on even rounds, try UNIX first */
- connection = try_unixpath (service_name, cfg);
- if (NULL != connection)
- return connection;
- }
- if (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
- {
- if ((GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT",
&port))
- || (port > 65535) ||
- (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME",
- &hostname)))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _
- ("Could not determine valid hostname and port for service `%s' from
configuration.\n"),
- service_name);
- return NULL;
- }
- if (0 == strlen (hostname))
- {
- GNUNET_free (hostname);
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("Need a non-empty hostname for service `%s'.\n"), service_name);
- return NULL;
- }
- }
- else
- {
- /* unspecified means 0 (disabled) */
- port = 0;
- hostname = NULL;
- }
- if (0 == port)
- {
- /* if port is 0, try UNIX */
- connection = try_unixpath (service_name, cfg);
- if (NULL != connection)
- {
- GNUNET_free_non_null (hostname);
- return connection;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Port is 0 for service `%s', UNIXPATH did not work, returning
NULL!\n",
- service_name);
- GNUNET_free_non_null (hostname);
- return NULL;
- }
- connection = GNUNET_CONNECTION_create_from_connect (cfg, hostname, port);
- GNUNET_free (hostname);
- return connection;
-}
-
-
-/**
- * Create a message queue to connect to a GNUnet service.
- * If handlers are specfied, receive messages from the connection.
- *
- * @param connection the client connection
- * @param handlers handlers for receiving messages, can be NULL
- * @param error_handler error handler
- * @param error_handler_cls closure for the @a error_handler
- * @return the message queue, NULL on error
- */
-struct GNUNET_MQ_Handle *
-GNUNET_CLIENT_connecTX (const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *service_name,
- const struct GNUNET_MQ_MessageHandler *handlers,
- GNUNET_MQ_ErrorHandler error_handler,
- void *error_handler_cls)
-{
- struct GNUNET_CLIENT_Connection *c;
-
- c = GNUNET_CLIENT_connect (service_name,
- cfg);
- if (NULL == c)
- return NULL;
- return GNUNET_MQ_queue_for_connection_client (c,
- handlers,
- error_handler,
- error_handler_cls);
-}
-
-
-/**
- * Get a connection with a service.
- *
- * @param service_name name of the service
- * @param cfg configuration to use
- * @return NULL on error (service unknown to configuration)
- */
-struct GNUNET_CLIENT_Connection *
-GNUNET_CLIENT_connect (const char *service_name,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- struct GNUNET_CLIENT_Connection *client;
- struct GNUNET_CONNECTION_Handle *connection;
-
- if (GNUNET_OK !=
- test_service_configuration (service_name,
- cfg))
- return NULL;
- connection = do_connect (service_name, cfg, 0);
- client = GNUNET_new (struct GNUNET_CLIENT_Connection);
- client->first_message = GNUNET_YES;
- client->attempts = 1;
- client->connection = connection;
- client->service_name = GNUNET_strdup (service_name);
- client->cfg = cfg;
- client->back_off = GNUNET_TIME_UNIT_MILLISECONDS;
- return client;
-}
-
-
-/**
- * Destroy connection with the service. This will automatically
- * cancel any pending "receive" request (however, the handler will
- * *NOT* be called, not even with a NULL message). Any pending
- * transmission request will also be cancelled UNLESS the callback for
- * the transmission request has already been called, in which case the
- * transmission 'finish_pending_write' argument determines whether or
- * not the write is guaranteed to complete before the socket is fully
- * destroyed (unless, of course, there is an error with the server in
- * which case the message may still be lost).
- *
- * @param client handle to the service connection
- */
-void
-GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *client)
-{
- if (GNUNET_YES == client->in_receive)
- {
- GNUNET_CONNECTION_receive_cancel (client->connection);
- client->in_receive = GNUNET_NO;
- }
- if (NULL != client->th)
- {
- GNUNET_CLIENT_notify_transmit_ready_cancel (client->th);
- client->th = NULL;
- }
- if (NULL != client->connection)
- {
- GNUNET_CONNECTION_destroy (client->connection);
- client->connection = NULL;
- }
- if (NULL != client->receive_task)
- {
- GNUNET_SCHEDULER_cancel (client->receive_task);
- client->receive_task = NULL;
- }
- client->receiver_handler = NULL;
- GNUNET_array_grow (client->received_buf,
- client->received_size,
- 0);
- GNUNET_free (client->service_name);
- GNUNET_free (client);
-}
-
-
-/**
- * Check if message is complete. Sets the "msg_complete" member
- * in the client struct.
- *
- * @param client connection with the buffer to check
- */
-static void
-check_complete (struct GNUNET_CLIENT_Connection *client)
-{
- if ((client->received_pos >= sizeof (struct GNUNET_MessageHeader)) &&
- (client->received_pos >=
- ntohs (((const struct GNUNET_MessageHeader *) client->received_buf)->
- size)))
- client->msg_complete = GNUNET_YES;
-}
-
-
-/**
- * Callback function for data received from the network. Note that
- * both @a available and @a errCode would be 0 if the read simply timed out.
- *
- * @param cls closure
- * @param buf pointer to received data
- * @param available number of bytes availabe in @a buf,
- * possibly 0 (on errors)
- * @param addr address of the sender
- * @param addrlen size of @a addr
- * @param errCode value of errno (on errors receiving)
- */
-static void
-receive_helper (void *cls,
- const void *buf,
- size_t available,
- const struct sockaddr *addr,
- socklen_t addrlen,
- int errCode)
-{
- struct GNUNET_CLIENT_Connection *client = cls;
- struct GNUNET_TIME_Relative remaining;
- GNUNET_CLIENT_MessageHandler receive_handler;
- void *receive_handler_cls;
-
- GNUNET_assert (GNUNET_NO == client->msg_complete);
- GNUNET_assert (GNUNET_YES == client->in_receive);
- client->in_receive = GNUNET_NO;
- if ( (0 == available) ||
- (NULL == client->connection) ||
- (0 != errCode) )
- {
- /* signal timeout! */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Timeout in receive_helper, available %u, client->connection %s,
errCode `%s'\n",
- (unsigned int) available,
- NULL == client->connection ? "NULL" : "non-NULL",
- STRERROR (errCode));
- /* remember failure */
- client->in_receive = GNUNET_SYSERR;
- if (NULL != (receive_handler = client->receiver_handler))
- {
- receive_handler_cls = client->receiver_handler_cls;
- client->receiver_handler = NULL;
- receive_handler (receive_handler_cls,
- NULL);
- }
- return;
- }
- /* FIXME: optimize for common fast case where buf contains the
- * entire message and we need no copying... */
-
- /* slow path: append to array */
- if (client->received_size < client->received_pos + available)
- GNUNET_array_grow (client->received_buf, client->received_size,
- client->received_pos + available);
- GNUNET_memcpy (&client->received_buf[client->received_pos], buf, available);
- client->received_pos += available;
- check_complete (client);
- /* check for timeout */
- remaining = GNUNET_TIME_absolute_get_remaining (client->receive_timeout);
- if (0 == remaining.rel_value_us)
- {
- /* signal timeout! */
- if (NULL != (receive_handler = client->receiver_handler))
- {
- client->receiver_handler = NULL;
- receive_handler (client->receiver_handler_cls, NULL);
- }
- return;
- }
- /* back to receive -- either for more data or to call callback! */
- GNUNET_CLIENT_receive (client, client->receiver_handler,
- client->receiver_handler_cls, remaining);
-}
-
-
-/**
- * Continuation to call the receive callback.
- *
- * @param cls our handle to the client connection
- */
-static void
-receive_task (void *cls)
-{
- struct GNUNET_CLIENT_Connection *client = cls;
- GNUNET_CLIENT_MessageHandler handler = client->receiver_handler;
- const struct GNUNET_MessageHeader *cmsg =
- (const struct GNUNET_MessageHeader *) client->received_buf;
- void *handler_cls = client->receiver_handler_cls;
- uint16_t msize = ntohs (cmsg->size);
- char mbuf[msize] GNUNET_ALIGN;
- struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) mbuf;
-
- client->receive_task = NULL;
- if ( (GNUNET_SYSERR == client->in_receive) &&
- (GNUNET_YES != client->msg_complete) )
- {
- /* Connection failure, signal to caller! */
- client->receiver_handler = NULL;
- if (NULL != handler)
- handler (handler_cls,
- NULL);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received message of type %u and size %u from %s service.\n",
- ntohs (cmsg->type),
- msize,
- client->service_name);
- GNUNET_assert (GNUNET_YES == client->msg_complete);
- GNUNET_assert (client->received_pos >= msize);
- GNUNET_memcpy (msg, cmsg, msize);
- memmove (client->received_buf,
- &client->received_buf[msize],
- client->received_pos - msize);
- client->received_pos -= msize;
- client->msg_complete = GNUNET_NO;
- client->receiver_handler = NULL;
- check_complete (client);
- if (NULL != handler)
- handler (handler_cls, msg);
-}
-
-
-/**
- * Read from the service.
- *
- * @param client the service
- * @param handler function to call with the message
- * @param handler_cls closure for @a handler
- * @param timeout how long to wait until timing out
- */
-void
-GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *client,
- GNUNET_CLIENT_MessageHandler handler,
- void *handler_cls,
- struct GNUNET_TIME_Relative timeout)
-{
- if (NULL == client->connection)
- {
- /* already disconnected, fail instantly! */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Client API violation for service `%s'\n",
- client->service_name);
- GNUNET_break (0); /* this should not happen in well-written
code! */
- if (NULL != handler)
- handler (handler_cls,
- NULL);
- return;
- }
- client->receiver_handler = handler;
- client->receiver_handler_cls = handler_cls;
- client->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
- if ( (GNUNET_YES == client->msg_complete) ||
- (GNUNET_SYSERR == client->in_receive) )
- {
- GNUNET_assert (NULL == client->receive_task);
- client->receive_task = GNUNET_SCHEDULER_add_now (&receive_task,
- client);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "calling GNUNET_CONNECTION_receive\n");
- GNUNET_assert (GNUNET_NO == client->in_receive);
- client->in_receive = GNUNET_YES;
- GNUNET_CONNECTION_receive (client->connection,
- GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
- timeout,
- &receive_helper,
- client);
-}
-
-
-/**
- * Handle for a test to check if a service is running.
- */
-struct GNUNET_CLIENT_TestHandle
-{
- /**
- * Function to call with the result of the test.
- */
- GNUNET_CLIENT_TestResultCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
-
- /**
- * Client connection we are using for the test, if any.
- */
- struct GNUNET_CLIENT_Connection *client;
-
- /**
- * Handle for the transmission request, if any.
- */
- struct GNUNET_CLIENT_TransmitHandle *th;
-
- /**
- * Deadline for calling @e cb.
- */
- struct GNUNET_TIME_Absolute test_deadline;
-
- /**
- * ID of task used for asynchronous operations.
- */
- struct GNUNET_SCHEDULER_Task *task;
-
- /**
- * Final result to report back (once known).
- */
- int result;
-};
-
-
-/**
- * Abort testing for service.
- *
- * @param th test handle
- */
-void
-GNUNET_CLIENT_service_test_cancel (struct GNUNET_CLIENT_TestHandle *th)
-{
- if (NULL != th->th)
- {
- GNUNET_CLIENT_notify_transmit_ready_cancel (th->th);
- th->th = NULL;
- }
- if (NULL != th->client)
- {
- GNUNET_CLIENT_disconnect (th->client);
- th->client = NULL;
- }
- if (NULL != th->task)
- {
- GNUNET_SCHEDULER_cancel (th->task);
- th->task = NULL;
- }
- GNUNET_free (th);
-}
-
-
-/**
- * Task that reports back the result by calling the callback
- * and then cleans up.
- *
- * @param cls the `struct GNUNET_CLIENT_TestHandle`
- */
-static void
-report_result (void *cls)
-{
- struct GNUNET_CLIENT_TestHandle *th = cls;
-
- th->task = NULL;
- th->cb (th->cb_cls, th->result);
- GNUNET_CLIENT_service_test_cancel (th);
-}
-
-
-/**
- * Report service test result asynchronously back to callback.
- *
- * @param th test handle with the result and the callback
- * @param result result to report
- */
-static void
-service_test_report (struct GNUNET_CLIENT_TestHandle *th,
- int result)
-{
- th->result = result;
- th->task = GNUNET_SCHEDULER_add_now (&report_result,
- th);
-}
-
-
-/**
- * Receive confirmation from test, service is up.
- *
- * @param cls closure with the `struct GNUNET_CLIENT_TestHandle`
- * @param msg message received, NULL on timeout or fatal error
- */
-static void
-confirm_handler (void *cls,
- const struct GNUNET_MessageHeader *msg)
-{
- struct GNUNET_CLIENT_TestHandle *th = cls;
-
- /* We may want to consider looking at the reply in more
- * detail in the future, for example, is this the
- * correct service? FIXME! */
- if (NULL != msg)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received confirmation that service is running.\n");
- service_test_report (th, GNUNET_YES);
- }
- else
- {
- service_test_report (th, GNUNET_NO);
- }
-}
-
-
-/**
- * Send the 'TEST' message to the service. If successful, prepare to
- * receive the reply.
- *
- * @param cls the `struct GNUNET_CLIENT_TestHandle` of the test
- * @param size number of bytes available in @a buf
- * @param buf where to write the message
- * @return number of bytes written to @a buf
- */
-static size_t
-write_test (void *cls, size_t size, void *buf)
-{
- struct GNUNET_CLIENT_TestHandle *th = cls;
- struct GNUNET_MessageHeader *msg;
-
- th->th = NULL;
- if (size < sizeof (struct GNUNET_MessageHeader))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Failed to transmit TEST request.\n");
- service_test_report (th, GNUNET_NO);
- return 0; /* client disconnected */
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Transmitting `%s' request.\n",
- "TEST");
- msg = (struct GNUNET_MessageHeader *) buf;
- msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
- msg->size = htons (sizeof (struct GNUNET_MessageHeader));
- GNUNET_CLIENT_receive (th->client,
- &confirm_handler, th,
- GNUNET_TIME_absolute_get_remaining
- (th->test_deadline));
- return sizeof (struct GNUNET_MessageHeader);
-}
-
-
-/**
- * Test if the service is running. If we are given a UNIXPATH or a
- * local address, we do this NOT by trying to connect to the service,
- * but by trying to BIND to the same port. If the BIND fails, we know
- * the service is running.
- *
- * @param service name of the service to wait for
- * @param cfg configuration to use
- * @param timeout how long to wait at most
- * @param cb function to call with the result
- * @param cb_cls closure for @a cb
- * @return handle to cancel the test
- */
-struct GNUNET_CLIENT_TestHandle *
-GNUNET_CLIENT_service_test (const char *service,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_CLIENT_TestResultCallback cb,
- void *cb_cls)
-{
- struct GNUNET_CLIENT_TestHandle *th;
- char *hostname;
- unsigned long long port;
- struct GNUNET_NETWORK_Handle *sock;
-
- th = GNUNET_new (struct GNUNET_CLIENT_TestHandle);
- th->cb = cb;
- th->cb_cls = cb_cls;
- th->test_deadline = GNUNET_TIME_relative_to_absolute (timeout);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Testing if service `%s' is running.\n",
- service);
-#ifdef AF_UNIX
- {
- /* probe UNIX support */
- struct sockaddr_un s_un;
- char *unixpath;
- int abstract;
-
- unixpath = NULL;
- if ((GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- service,
- "UNIXPATH",
- &unixpath)) &&
- (0 < strlen (unixpath))) /* We have a non-NULL unixpath, does that
mean it's valid? */
- {
- if (strlen (unixpath) >= sizeof (s_un.sun_path))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("UNIXPATH `%s' too long, maximum length is %llu\n"),
- unixpath,
- (unsigned long long) sizeof (s_un.sun_path));
- unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Using `%s' instead\n"), unixpath);
- }
- }
-#ifdef LINUX
- abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
- "TESTING",
- "USE_ABSTRACT_SOCKETS");
-#else
- abstract = GNUNET_NO;
-#endif
- if ((NULL != unixpath) && (GNUNET_YES != abstract))
- {
- if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (unixpath))
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "mkdir", unixpath);
- }
- if (NULL != unixpath)
- {
- sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
- if (NULL != sock)
- {
- memset (&s_un, 0, sizeof (s_un));
- s_un.sun_family = AF_UNIX;
- strncpy (s_un.sun_path, unixpath, sizeof (s_un.sun_path) - 1);
- if (GNUNET_YES == abstract)
- s_un.sun_path[0] = '\0';
-#if HAVE_SOCKADDR_IN_SIN_LEN
- s_un.sun_len = (u_char) sizeof (struct sockaddr_un);
-#endif
- if (GNUNET_OK !=
- GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_un,
- sizeof (struct sockaddr_un)))
- {
- /* failed to bind => service must be running */
- GNUNET_free (unixpath);
- (void) GNUNET_NETWORK_socket_close (sock);
- service_test_report (th, GNUNET_YES);
- return th;
- }
- (void) GNUNET_NETWORK_socket_close (sock);
- /* let's try IP */
- }
- }
- GNUNET_free_non_null (unixpath);
- }
-#endif
-
- hostname = NULL;
- if ((GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg, service, "PORT", &port)) ||
- (port > 65535) ||
- (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg, service, "HOSTNAME",
- &hostname)))
- {
- /* UNIXPATH failed (if possible) AND IP failed => error */
- service_test_report (th, GNUNET_SYSERR);
- return th;
- }
-
- if (0 == strcmp ("localhost", hostname)
-#if !LINUX
- && 0
-#endif
- )
- {
- /* can test using 'bind' */
- struct sockaddr_in s_in;
-
- memset (&s_in, 0, sizeof (s_in));
-#if HAVE_SOCKADDR_IN_SIN_LEN
- s_in.sin_len = sizeof (struct sockaddr_in);
-#endif
- s_in.sin_family = AF_INET;
- s_in.sin_port = htons (port);
-
- sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
- if (NULL != sock)
- {
- if (GNUNET_OK !=
- GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in,
- sizeof (s_in)))
- {
- /* failed to bind => service must be running */
- GNUNET_free (hostname);
- (void) GNUNET_NETWORK_socket_close (sock);
- service_test_report (th, GNUNET_YES);
- return th;
- }
- (void) GNUNET_NETWORK_socket_close (sock);
- }
- }
-
- if (0 == strcmp ("ip6-localhost", hostname)
-#if !LINUX
- && 0
-#endif
- )
- {
- /* can test using 'bind' */
- struct sockaddr_in6 s_in6;
-
- memset (&s_in6, 0, sizeof (s_in6));
-#if HAVE_SOCKADDR_IN_SIN_LEN
- s_in6.sin6_len = sizeof (struct sockaddr_in6);
-#endif
- s_in6.sin6_family = AF_INET6;
- s_in6.sin6_port = htons (port);
-
- sock = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0);
- if (NULL != sock)
- {
- if (GNUNET_OK !=
- GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in6,
- sizeof (s_in6)))
- {
- /* failed to bind => service must be running */
- GNUNET_free (hostname);
- (void) GNUNET_NETWORK_socket_close (sock);
- service_test_report (th, GNUNET_YES);
- return th;
- }
- (void) GNUNET_NETWORK_socket_close (sock);
- }
- }
-
- if (((0 == strcmp ("localhost", hostname)) ||
- (0 == strcmp ("ip6-localhost", hostname)))
-#if !LINUX
- && 0
-#endif
- )
- {
- /* all binds succeeded => claim service not running right now */
- GNUNET_free_non_null (hostname);
- service_test_report (th, GNUNET_NO);
- return th;
- }
- GNUNET_free_non_null (hostname);
-
- /* non-localhost, try 'connect' method */
- th->client = GNUNET_CLIENT_connect (service, cfg);
- if (NULL == th->client)
- {
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Could not connect to service `%s', configuration broken.\n"),
- service);
- service_test_report (th, GNUNET_SYSERR);
- return th;
- }
- th->th = GNUNET_CLIENT_notify_transmit_ready (th->client,
- sizeof (struct
GNUNET_MessageHeader),
- timeout, GNUNET_YES,
- &write_test, th);
- if (NULL == th->th)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("Failure to transmit request to service `%s'\n"), service);
- service_test_report (th, GNUNET_SYSERR);
- return th;
- }
- return th;
-}
-
-
-/**
- * Connection notifies us about failure or success of
- * a transmission request. Either pass it on to our
- * user or, if possible, retry.
- *
- * @param cls our `struct GNUNET_CLIENT_TransmissionHandle`
- * @param size number of bytes available for transmission
- * @param buf where to write them
- * @return number of bytes written to @a buf
- */
-static size_t
-client_notify (void *cls, size_t size, void *buf);
-
-
-/**
- * This task is run if we should re-try connection to the
- * service after a while.
- *
- * @param cls our `struct GNUNET_CLIENT_TransmitHandle` of the request
- */
-static void
-client_delayed_retry (void *cls)
-{
- struct GNUNET_CLIENT_TransmitHandle *th = cls;
- struct GNUNET_TIME_Relative delay;
-
- th->reconnect_task = NULL;
- th->client->connection =
- do_connect (th->client->service_name,
- th->client->cfg,
- th->client->attempts++);
- th->client->first_message = GNUNET_YES;
- if (NULL == th->client->connection)
- {
- /* could happen if we're out of sockets */
- delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining
(th->timeout),
- th->client->back_off);
- th->client->back_off = GNUNET_TIME_STD_BACKOFF (th->client->back_off);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Transmission failed %u times, trying again in %s.\n",
- MAX_ATTEMPTS - th->attempts_left,
- GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
- GNUNET_assert (NULL == th->th);
- GNUNET_assert (NULL == th->reconnect_task);
- th->reconnect_task =
- GNUNET_SCHEDULER_add_delayed (delay,
- &client_delayed_retry,
- th);
- return;
- }
- th->th =
- GNUNET_CONNECTION_notify_transmit_ready (th->client->connection,
th->size,
-
GNUNET_TIME_absolute_get_remaining
- (th->timeout),
- &client_notify,
- th);
- if (NULL == th->th)
- {
- GNUNET_break (0);
- th->client->th = NULL;
- th->notify (th->notify_cls, 0, NULL);
- GNUNET_free (th);
- return;
- }
-}
-
-
-/**
- * Connection notifies us about failure or success of a transmission
- * request. Either pass it on to our user or, if possible, retry.
- *
- * @param cls our `struct GNUNET_CLIENT_TransmissionHandle`
- * @param size number of bytes available for transmission
- * @param buf where to write them
- * @return number of bytes written to @a buf
- */
-static size_t
-client_notify (void *cls,
- size_t size,
- void *buf)
-{
- struct GNUNET_CLIENT_TransmitHandle *th = cls;
- struct GNUNET_CLIENT_Connection *client = th->client;
- size_t ret;
- struct GNUNET_TIME_Relative delay;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "client_notify is running\n");
- th->th = NULL;
- client->th = NULL;
- if (NULL == buf)
- {
- delay = GNUNET_TIME_absolute_get_remaining (th->timeout);
- delay.rel_value_us /= 2;
- if ( (GNUNET_YES != th->auto_retry) ||
- (0 == --th->attempts_left) ||
- (delay.rel_value_us < 1) )
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Transmission failed %u times, giving up.\n",
- MAX_ATTEMPTS - th->attempts_left);
- GNUNET_break (0 ==
- th->notify (th->notify_cls, 0, NULL));
- GNUNET_free (th);
- return 0;
- }
- /* auto-retry */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Failed to connect to `%s', automatically trying again.\n",
- client->service_name);
- if (GNUNET_YES == client->in_receive)
- {
- GNUNET_CONNECTION_receive_cancel (client->connection);
- client->in_receive = GNUNET_NO;
- }
- GNUNET_CONNECTION_destroy (client->connection);
- client->connection = NULL;
- delay = GNUNET_TIME_relative_min (delay, client->back_off);
- client->back_off =
- GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply
- (client->back_off, 2),
- GNUNET_TIME_UNIT_SECONDS);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Transmission failed %u times, trying again in %s.\n",
- MAX_ATTEMPTS - th->attempts_left,
- GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
- client->th = th;
- GNUNET_assert (NULL == th->reconnect_task);
- GNUNET_assert (NULL == th->th);
- th->reconnect_task =
- GNUNET_SCHEDULER_add_delayed (delay,
- &client_delayed_retry,
- th);
- return 0;
- }
- GNUNET_assert (size >= th->size);
- ret = th->notify (th->notify_cls, size, buf);
- GNUNET_free (th);
- if (sizeof (struct GNUNET_MessageHeader) <= ret)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Transmitting message of type %u and size %u to %s service.\n",
- ntohs (((struct GNUNET_MessageHeader *) buf)->type),
- ntohs (((struct GNUNET_MessageHeader *) buf)->size),
- client->service_name);
- }
- return ret;
-}
-
-
-/**
- * Ask the client to call us once the specified number of bytes
- * are free in the transmission buffer. Will never call the @a notify
- * callback in this task, but always first go into the scheduler.
- *
- * @param client connection to the service
- * @param size number of bytes to send
- * @param timeout after how long should we give up (and call
- * notify with buf NULL and size 0)?
- * @param auto_retry if the connection to the service dies, should we
- * automatically re-connect and retry (within the timeout period)
- * or should we immediately fail in this case? Pass GNUNET_YES
- * if the caller does not care about temporary connection errors,
- * for example because the protocol is stateless
- * @param notify function to call
- * @param notify_cls closure for @a notify
- * @return NULL if our buffer will never hold size bytes,
- * a handle if the notify callback was queued (can be used to cancel)
- */
-struct GNUNET_CLIENT_TransmitHandle *
-GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client,
- size_t size,
- struct GNUNET_TIME_Relative timeout,
- int auto_retry,
- GNUNET_CONNECTION_TransmitReadyNotify
notify,
- void *notify_cls)
-{
- struct GNUNET_CLIENT_TransmitHandle *th;
-
- if (NULL != client->th)
- {
- /* If this breaks, you most likley called this function twice without
waiting
- * for completion or canceling the request */
- GNUNET_assert (0);
- return NULL;
- }
- th = GNUNET_new (struct GNUNET_CLIENT_TransmitHandle);
- th->client = client;
- th->size = size;
- th->timeout = GNUNET_TIME_relative_to_absolute (timeout);
- /* always auto-retry on first message to service */
- th->auto_retry = (GNUNET_YES == client->first_message) ? GNUNET_YES :
auto_retry;
- client->first_message = GNUNET_NO;
- th->notify = notify;
- th->notify_cls = notify_cls;
- th->attempts_left = MAX_ATTEMPTS;
- client->th = th;
- if (NULL == client->connection)
- {
- GNUNET_assert (NULL == th->th);
- GNUNET_assert (NULL == th->reconnect_task);
- th->reconnect_task =
- GNUNET_SCHEDULER_add_delayed (client->back_off,
- &client_delayed_retry,
- th);
- }
- else
- {
- th->th = GNUNET_CONNECTION_notify_transmit_ready (client->connection,
- size,
- timeout,
- &client_notify,
- th);
- if (NULL == th->th)
- {
- GNUNET_break (0);
- GNUNET_free (th);
- client->th = NULL;
- return NULL;
- }
- }
- return th;
-}
-
-
-/**
- * Cancel a request for notification.
- *
- * @param th handle from the original request.
- */
-void
-GNUNET_CLIENT_notify_transmit_ready_cancel (struct
GNUNET_CLIENT_TransmitHandle *th)
-{
- if (NULL != th->reconnect_task)
- {
- GNUNET_assert (NULL == th->th);
- GNUNET_SCHEDULER_cancel (th->reconnect_task);
- th->reconnect_task = NULL;
- }
- else
- {
- GNUNET_assert (NULL != th->th);
- GNUNET_CONNECTION_notify_transmit_ready_cancel (th->th);
- }
- th->client->th = NULL;
- GNUNET_free (th);
-}
-
-
-/* end of client.c */
Modified: gnunet/src/util/mq.c
===================================================================
--- gnunet/src/util/mq.c 2016-10-23 16:03:36 UTC (rev 38185)
+++ gnunet/src/util/mq.c 2016-10-23 16:03:54 UTC (rev 38186)
@@ -220,34 +220,6 @@
/**
- * Implementation-specific state for connection to
- * service (MQ for clients).
- */
-struct ClientConnectionState
-{
- /**
- * Did we call receive alread alreadyy?
- */
- int receive_active;
-
- /**
- * Do we also want to receive?
- */
- int receive_requested;
-
- /**
- * Connection to the service.
- */
- struct GNUNET_CLIENT_Connection *connection;
-
- /**
- * Active transmission request (or NULL).
- */
- struct GNUNET_CLIENT_TransmitHandle *th;
-};
-
-
-/**
* Call the message message handler that was registered
* for the type of the given message in the given message queue.
*
@@ -775,175 +747,6 @@
/**
- * Type of a function to call when we receive a message
- * from the service.
- *
- * @param cls closure
- * @param msg message received, NULL on timeout or fatal error
- */
-static void
-handle_client_message (void *cls,
- const struct GNUNET_MessageHeader *msg)
-{
- struct GNUNET_MQ_Handle *mq = cls;
- struct ClientConnectionState *state;
-
- state = mq->impl_state;
- if (NULL == msg)
- {
- GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_READ);
- return;
- }
- GNUNET_CLIENT_receive (state->connection,
- &handle_client_message,
- mq,
- GNUNET_TIME_UNIT_FOREVER_REL);
- GNUNET_MQ_inject_message (mq, msg);
-}
-
-
-/**
- * Transmit a queued message to the session's client.
- *
- * @param cls consensus session
- * @param size number of bytes available in @a buf
- * @param buf where the callee should write the message
- * @return number of bytes written to buf
- */
-static size_t
-connection_client_transmit_queued (void *cls,
- size_t size,
- void *buf)
-{
- struct GNUNET_MQ_Handle *mq = cls;
- const struct GNUNET_MessageHeader *msg;
- struct ClientConnectionState *state = mq->impl_state;
- size_t msg_size;
-
- GNUNET_assert (NULL != mq);
- state->th = NULL;
- msg = GNUNET_MQ_impl_current (mq);
-
- if (NULL == buf)
- {
- GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_READ);
- return 0;
- }
-
- if ( (GNUNET_YES == state->receive_requested) &&
- (GNUNET_NO == state->receive_active) )
- {
- state->receive_active = GNUNET_YES;
- GNUNET_CLIENT_receive (state->connection,
- &handle_client_message,
- mq,
- GNUNET_TIME_UNIT_FOREVER_REL);
- }
-
- msg_size = ntohs (msg->size);
- GNUNET_assert (size >= msg_size);
- GNUNET_memcpy (buf, msg, msg_size);
- state->th = NULL;
-
- GNUNET_MQ_impl_send_continue (mq);
-
- return msg_size;
-}
-
-
-static void
-connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
- void *impl_state)
-{
- struct ClientConnectionState *state = impl_state;
-
- if (NULL != state->th)
- {
- GNUNET_CLIENT_notify_transmit_ready_cancel (state->th);
- state->th = NULL;
- }
- GNUNET_CLIENT_disconnect (state->connection);
- GNUNET_free (impl_state);
-}
-
-
-static void
-connection_client_send_impl (struct GNUNET_MQ_Handle *mq,
- const struct GNUNET_MessageHeader *msg,
- void *impl_state)
-{
- struct ClientConnectionState *state = impl_state;
-
- GNUNET_assert (NULL != state);
- GNUNET_assert (NULL == state->th);
- state->th =
- GNUNET_CLIENT_notify_transmit_ready (state->connection,
- ntohs (msg->size),
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_NO,
- &connection_client_transmit_queued,
- mq);
- GNUNET_assert (NULL != state->th);
-}
-
-
-static void
-connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
- void *impl_state)
-{
- struct ClientConnectionState *state = impl_state;
-
- if (NULL != state->th)
- {
- GNUNET_CLIENT_notify_transmit_ready_cancel (state->th);
- state->th = NULL;
- }
- else if (NULL != mq->send_task)
- {
- GNUNET_SCHEDULER_cancel (mq->send_task);
- mq->send_task = NULL;
- }
- else
- GNUNET_assert (0);
-}
-
-
-struct GNUNET_MQ_Handle *
-GNUNET_MQ_queue_for_connection_client (struct GNUNET_CLIENT_Connection
*connection,
- const struct GNUNET_MQ_MessageHandler
*handlers,
- GNUNET_MQ_ErrorHandler error_handler,
- void *error_handler_cls)
-{
- struct GNUNET_MQ_Handle *mq;
- struct ClientConnectionState *state;
- unsigned int i;
-
- mq = GNUNET_new (struct GNUNET_MQ_Handle);
- if (NULL != handlers)
- {
- for (i=0;NULL != handlers[i].cb; i++) ;
- mq->handlers = GNUNET_new_array (i + 1,
- struct GNUNET_MQ_MessageHandler);
- GNUNET_memcpy (mq->handlers,
- handlers,
- i * sizeof (struct GNUNET_MQ_MessageHandler));
- }
- mq->error_handler = error_handler;
- mq->error_handler_cls = error_handler_cls;
- state = GNUNET_new (struct ClientConnectionState);
- state->connection = connection;
- mq->impl_state = state;
- mq->send_impl = &connection_client_send_impl;
- mq->destroy_impl = &connection_client_destroy_impl;
- mq->cancel_impl = &connection_client_cancel_impl;
- if (NULL != handlers)
- state->receive_requested = GNUNET_YES;
-
- return mq;
-}
-
-
-/**
* Associate the assoc_data in mq with a unique request id.
*
* @param mq message queue, id will be unique for the queue
Deleted: gnunet/src/util/service.c
===================================================================
--- gnunet/src/util/service.c 2016-10-23 16:03:36 UTC (rev 38185)
+++ gnunet/src/util/service.c 2016-10-23 16:03:54 UTC (rev 38186)
@@ -1,1697 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2009, 2012 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/service.c
- * @brief functions related to starting services
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_protocols.h"
-#include "gnunet_constants.h"
-#include "gnunet_resolver_service.h"
-#include "speedup.h"
-
-#if HAVE_MALLINFO
-#include <malloc.h>
-#include "gauger.h"
-#endif
-
-
-#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
-
-#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util",
syscall)
-
-#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file
(kind, "util", syscall, filename)
-
-
-/* ******************* access control ******************** */
-
-/**
- * Check if the given IP address is in the list of IP addresses.
- *
- * @param list a list of networks
- * @param add the IP to check (in network byte order)
- * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
- */
-static int
-check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
- const struct in_addr *add)
-{
- unsigned int i;
-
- if (NULL == list)
- return GNUNET_NO;
- i = 0;
- while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
- {
- if ((add->s_addr & list[i].netmask.s_addr) ==
- (list[i].network.s_addr & list[i].netmask.s_addr))
- return GNUNET_YES;
- i++;
- }
- return GNUNET_NO;
-}
-
-
-/**
- * Check if the given IP address is in the list of IP addresses.
- *
- * @param list a list of networks
- * @param ip the IP to check (in network byte order)
- * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
- */
-static int
-check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
- const struct in6_addr *ip)
-{
- unsigned int i;
- unsigned int j;
- struct in6_addr zero;
-
- if (NULL == list)
- return GNUNET_NO;
- memset (&zero, 0, sizeof (struct in6_addr));
- i = 0;
-NEXT:
- while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr)))
- {
- for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
- if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
- (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
- {
- i++;
- goto NEXT;
- }
- return GNUNET_YES;
- }
- return GNUNET_NO;
-}
-
-
-/* ****************** service struct ****************** */
-
-
-/**
- * Context for "service_task".
- */
-struct GNUNET_SERVICE_Context
-{
- /**
- * Our configuration.
- */
- const struct GNUNET_CONFIGURATION_Handle *cfg;
-
- /**
- * Handle for the server.
- */
- struct GNUNET_SERVER_Handle *server;
-
- /**
- * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
- * listen sockets.
- */
- struct sockaddr **addrs;
-
- /**
- * Name of our service.
- */
- const char *service_name;
-
- /**
- * Main service-specific task to run.
- */
- GNUNET_SERVICE_Main task;
-
- /**
- * Closure for @e task.
- */
- void *task_cls;
-
- /**
- * IPv4 addresses that are not allowed to connect.
- */
- struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
-
- /**
- * IPv6 addresses that are not allowed to connect.
- */
- struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
-
- /**
- * IPv4 addresses that are allowed to connect (if not
- * set, all are allowed).
- */
- struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
-
- /**
- * IPv6 addresses that are allowed to connect (if not
- * set, all are allowed).
- */
- struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
-
- /**
- * My (default) message handlers. Adjusted copy
- * of "defhandlers".
- */
- struct GNUNET_SERVER_MessageHandler *my_handlers;
-
- /**
- * Array of the lengths of the entries in addrs.
- */
- socklen_t *addrlens;
-
- /**
- * NULL-terminated array of listen sockets we should take over.
- */
- struct GNUNET_NETWORK_Handle **lsocks;
-
- /**
- * Task ID of the shutdown task.
- */
- struct GNUNET_SCHEDULER_Task *shutdown_task;
-
- /**
- * Idle timeout for server.
- */
- struct GNUNET_TIME_Relative timeout;
-
- /**
- * Overall success/failure of the service start.
- */
- int ret;
-
- /**
- * If we are daemonizing, this FD is set to the
- * pipe to the parent. Send '.' if we started
- * ok, '!' if not. -1 if we are not daemonizing.
- */
- int ready_confirm_fd;
-
- /**
- * Do we close connections if we receive messages
- * for which we have no handler?
- */
- int require_found;
-
- /**
- * Do we require a matching UID for UNIX domain socket connections?
- * #GNUNET_NO means that the UID does not have to match (however,
- * @e match_gid may still impose other access control checks).
- */
- int match_uid;
-
- /**
- * Do we require a matching GID for UNIX domain socket connections?
- * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
- * checking that the client's UID is in our group OR that the
- * client's GID is our GID. If both "match_gid" and @e match_uid are
- * #GNUNET_NO, all users on the local system have access.
- */
- int match_gid;
-
- /**
- * Our options.
- */
- enum GNUNET_SERVICE_Options options;
-
-};
-
-
-/* ****************** message handlers ****************** */
-
-/**
- * Send a 'TEST' message back to the client.
- *
- * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
- * @param size number of bytes available in 'buf'
- * @param buf where to copy the message
- * @return number of bytes written to 'buf'
- */
-static size_t
-write_test (void *cls, size_t size, void *buf)
-{
- struct GNUNET_SERVER_Client *client = cls;
- struct GNUNET_MessageHeader *msg;
-
- if (size < sizeof (struct GNUNET_MessageHeader))
- {
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return 0; /* client disconnected */
- }
- msg = (struct GNUNET_MessageHeader *) buf;
- msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
- msg->size = htons (sizeof (struct GNUNET_MessageHeader));
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return sizeof (struct GNUNET_MessageHeader);
-}
-
-
-/**
- * Handler for TEST message.
- *
- * @param cls closure (refers to service)
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_test (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- /* simply bounce message back to acknowledge */
- if (NULL ==
- GNUNET_SERVER_notify_transmit_ready (client,
- sizeof (struct
GNUNET_MessageHeader),
- GNUNET_TIME_UNIT_FOREVER_REL,
- &write_test, client))
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-}
-
-
-/**
- * Default handlers for all services. Will be copied and the
- * "callback_cls" fields will be replaced with the specific service
- * struct.
- */
-static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
- {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
- sizeof (struct GNUNET_MessageHeader)},
- {NULL, NULL, 0, 0}
-};
-
-
-/* ****************** service core routines ************** */
-
-
-/**
- * Check if access to the service is allowed from the given address.
- *
- * @param cls closure
- * @param uc credentials, if available, otherwise NULL
- * @param addr address
- * @param addrlen length of address
- * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR
- * for unknown address family (will be denied).
- */
-static int
-check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
- const struct sockaddr *addr, socklen_t addrlen)
-{
- struct GNUNET_SERVICE_Context *sctx = cls;
- const struct sockaddr_in *i4;
- const struct sockaddr_in6 *i6;
- int ret;
-
- switch (addr->sa_family)
- {
- case AF_INET:
- GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
- i4 = (const struct sockaddr_in *) addr;
- ret = ((NULL == sctx->v4_allowed) ||
- (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
- ((NULL == sctx->v4_denied) ||
- (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
- break;
- case AF_INET6:
- GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
- i6 = (const struct sockaddr_in6 *) addr;
- ret = ((NULL == sctx->v6_allowed) ||
- (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
- ((NULL == sctx->v6_denied) ||
- (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
- break;
-#ifndef WINDOWS
- case AF_UNIX:
- ret = GNUNET_OK; /* controlled using file-system ACL now */
- break;
-#endif
- default:
- LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
- addr->sa_family);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK != ret)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("Access from `%s' denied to service `%s'\n"),
- GNUNET_a2s (addr, addrlen),
- sctx->service_name);
- }
- return ret;
-}
-
-
-/**
- * Get the name of the file where we will
- * write the PID of the service.
- *
- * @param sctx service context
- * @return name of the file for the process ID
- */
-static char *
-get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
-{
- char *pif;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
- "PIDFILE", &pif))
- return NULL;
- return pif;
-}
-
-
-/**
- * Parse an IPv4 access control list.
- *
- * @param ret location where to write the ACL (set)
- * @param sctx service context to use to get the configuration
- * @param option name of the ACL option to parse
- * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
- * no ACL configured)
- */
-static int
-process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
- struct GNUNET_SERVICE_Context *sctx,
- const char *option)
-{
- char *opt;
-
- if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
- {
- *ret = NULL;
- return GNUNET_OK;
- }
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
- sctx->service_name,
- option, &opt));
- if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
- opt, sctx->service_name, option);
- GNUNET_free (opt);
- return GNUNET_SYSERR;
- }
- GNUNET_free (opt);
- return GNUNET_OK;
-}
-
-
-/**
- * Parse an IPv6 access control list.
- *
- * @param ret location where to write the ACL (set)
- * @param sctx service context to use to get the configuration
- * @param option name of the ACL option to parse
- * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
- * no ACL configured)
- */
-static int
-process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
- struct GNUNET_SERVICE_Context *sctx,
- const char *option)
-{
- char *opt;
-
- if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
- {
- *ret = NULL;
- return GNUNET_OK;
- }
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
- sctx->service_name,
- option, &opt));
- if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
- opt, sctx->service_name, option);
- GNUNET_free (opt);
- return GNUNET_SYSERR;
- }
- GNUNET_free (opt);
- return GNUNET_OK;
-}
-
-
-/**
- * Add the given UNIX domain path as an address to the
- * list (as the first entry).
- *
- * @param saddrs array to update
- * @param saddrlens where to store the address length
- * @param unixpath path to add
- * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
- * parameter is ignore on systems other than LINUX
- */
-static void
-add_unixpath (struct sockaddr **saddrs,
- socklen_t *saddrlens,
- const char *unixpath,
- int abstract)
-{
-#ifdef AF_UNIX
- struct sockaddr_un *un;
-
- un = GNUNET_new (struct sockaddr_un);
- un->sun_family = AF_UNIX;
- strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
-#ifdef LINUX
- if (GNUNET_YES == abstract)
- un->sun_path[0] = '\0';
-#endif
-#if HAVE_SOCKADDR_IN_SIN_LEN
- un->sun_len = (u_char) sizeof (struct sockaddr_un);
-#endif
- *saddrs = (struct sockaddr *) un;
- *saddrlens = sizeof (struct sockaddr_un);
-#else
- /* this function should never be called
- * unless AF_UNIX is defined! */
- GNUNET_assert (0);
-#endif
-}
-
-
-/**
- * Get the list of addresses that a server for the given service
- * should bind to.
- *
- * @param service_name name of the service
- * @param cfg configuration (which specifies the addresses)
- * @param addrs set (call by reference) to an array of pointers to the
- * addresses the server should bind to and listen on; the
- * array will be NULL-terminated (on success)
- * @param addr_lens set (call by reference) to an array of the lengths
- * of the respective `struct sockaddr` struct in the @a addrs
- * array (on success)
- * @return number of addresses found on success,
- * #GNUNET_SYSERR if the configuration
- * did not specify reasonable finding information or
- * if it specified a hostname that could not be resolved;
- * #GNUNET_NO if the number of addresses configured is
- * zero (in this case, `*addrs` and `*addr_lens` will be
- * set to NULL).
- */
-int
-GNUNET_SERVICE_get_server_addresses (const char *service_name,
- const struct GNUNET_CONFIGURATION_Handle
*cfg,
- struct sockaddr ***addrs,
- socklen_t ** addr_lens)
-{
- int disablev6;
- struct GNUNET_NETWORK_Handle *desc;
- unsigned long long port;
- char *unixpath;
- struct addrinfo hints;
- struct addrinfo *res;
- struct addrinfo *pos;
- struct addrinfo *next;
- unsigned int i;
- int resi;
- int ret;
- int abstract;
- struct sockaddr **saddrs;
- socklen_t *saddrlens;
- char *hostname;
-
- *addrs = NULL;
- *addr_lens = NULL;
- desc = NULL;
- if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
- {
- if (GNUNET_SYSERR ==
- (disablev6 =
- GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name,
"DISABLEV6")))
- return GNUNET_SYSERR;
- }
- else
- disablev6 = GNUNET_NO;
-
- if (! disablev6)
- {
- /* probe IPv6 support */
- desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
- if (NULL == desc)
- {
- if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
- (EACCES == errno))
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
- return GNUNET_SYSERR;
- }
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Disabling IPv6 support for service `%s', failed to create IPv6
socket: %s\n"),
- service_name, STRERROR (errno));
- disablev6 = GNUNET_YES;
- }
- else
- {
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
- desc = NULL;
- }
- }
-
- port = 0;
- if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
- {
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
- "PORT", &port))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Require valid port number for service `%s' in configuration!\n"),
- service_name);
- }
- if (port > 65535)
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Require valid port number for service `%s' in configuration!\n"),
- service_name);
- return GNUNET_SYSERR;
- }
- }
-
- if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
- {
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
- "BINDTO", &hostname));
- }
- else
- hostname = NULL;
-
- unixpath = NULL;
- abstract = GNUNET_NO;
-#ifdef AF_UNIX
- if ((GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
- (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
- &unixpath)) &&
- (0 < strlen (unixpath)))
- {
- /* probe UNIX support */
- struct sockaddr_un s_un;
-
- if (strlen (unixpath) >= sizeof (s_un.sun_path))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
- (unsigned long long) sizeof (s_un.sun_path));
- unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Using `%s' instead\n"),
- unixpath);
- }
-#ifdef LINUX
- abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
- "TESTING",
- "USE_ABSTRACT_SOCKETS");
- if (GNUNET_SYSERR == abstract)
- abstract = GNUNET_NO;
-#endif
- if ((GNUNET_YES != abstract)
- && (GNUNET_OK !=
- GNUNET_DISK_directory_create_for_file (unixpath)))
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "mkdir",
- unixpath);
- }
- if (NULL != unixpath)
- {
- desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
- if (NULL == desc)
- {
- if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
- (EACCES == errno))
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
- GNUNET_free_non_null (hostname);
- GNUNET_free (unixpath);
- return GNUNET_SYSERR;
- }
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Disabling UNIX domain socket support for service `%s', failed to
create UNIX domain socket: %s\n"),
- service_name,
- STRERROR (errno));
- GNUNET_free (unixpath);
- unixpath = NULL;
- }
- else
- {
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
- desc = NULL;
- }
- }
-#endif
-
- if ((0 == port) && (NULL == unixpath))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Have neither PORT nor UNIXPATH for service `%s', but one is
required\n"),
- service_name);
- GNUNET_free_non_null (hostname);
- return GNUNET_SYSERR;
- }
- if (0 == port)
- {
- saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
- saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
- add_unixpath (saddrs, saddrlens, unixpath, abstract);
- GNUNET_free_non_null (unixpath);
- GNUNET_free_non_null (hostname);
- *addrs = saddrs;
- *addr_lens = saddrlens;
- return 1;
- }
-
- if (NULL != hostname)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Resolving `%s' since that is where `%s' will bind to.\n",
- hostname,
- service_name);
- memset (&hints, 0, sizeof (struct addrinfo));
- if (disablev6)
- hints.ai_family = AF_INET;
- hints.ai_protocol = IPPROTO_TCP;
- if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
- (NULL == res))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to resolve `%s': %s\n"),
- hostname,
- gai_strerror (ret));
- GNUNET_free (hostname);
- GNUNET_free_non_null (unixpath);
- return GNUNET_SYSERR;
- }
- next = res;
- i = 0;
- while (NULL != (pos = next))
- {
- next = pos->ai_next;
- if ((disablev6) && (pos->ai_family == AF_INET6))
- continue;
- i++;
- }
- if (0 == i)
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to find %saddress for `%s'.\n"),
- disablev6 ? "IPv4 " : "",
- hostname);
- freeaddrinfo (res);
- GNUNET_free (hostname);
- GNUNET_free_non_null (unixpath);
- return GNUNET_SYSERR;
- }
- resi = i;
- if (NULL != unixpath)
- resi++;
- saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
- saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
- i = 0;
- if (NULL != unixpath)
- {
- add_unixpath (saddrs, saddrlens, unixpath, abstract);
- i++;
- }
- next = res;
- while (NULL != (pos = next))
- {
- next = pos->ai_next;
- if ((disablev6) && (AF_INET6 == pos->ai_family))
- continue;
- if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
- continue; /* not TCP */
- if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
- continue; /* huh? */
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
- service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
- if (AF_INET == pos->ai_family)
- {
- GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
- saddrlens[i] = pos->ai_addrlen;
- saddrs[i] = GNUNET_malloc (saddrlens[i]);
- GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
- ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
- }
- else
- {
- GNUNET_assert (AF_INET6 == pos->ai_family);
- GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
- saddrlens[i] = pos->ai_addrlen;
- saddrs[i] = GNUNET_malloc (saddrlens[i]);
- GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
- ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
- }
- i++;
- }
- GNUNET_free (hostname);
- freeaddrinfo (res);
- resi = i;
- }
- else
- {
- /* will bind against everything, just set port */
- if (disablev6)
- {
- /* V4-only */
- resi = 1;
- if (NULL != unixpath)
- resi++;
- i = 0;
- saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
- saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
- if (NULL != unixpath)
- {
- add_unixpath (saddrs, saddrlens, unixpath, abstract);
- i++;
- }
- saddrlens[i] = sizeof (struct sockaddr_in);
- saddrs[i] = GNUNET_malloc (saddrlens[i]);
-#if HAVE_SOCKADDR_IN_SIN_LEN
- ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
-#endif
- ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
- ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
- }
- else
- {
- /* dual stack */
- resi = 2;
- if (NULL != unixpath)
- resi++;
- saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
- saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
- i = 0;
- if (NULL != unixpath)
- {
- add_unixpath (saddrs, saddrlens, unixpath, abstract);
- i++;
- }
- saddrlens[i] = sizeof (struct sockaddr_in6);
- saddrs[i] = GNUNET_malloc (saddrlens[i]);
-#if HAVE_SOCKADDR_IN_SIN_LEN
- ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
-#endif
- ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
- ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
- i++;
- saddrlens[i] = sizeof (struct sockaddr_in);
- saddrs[i] = GNUNET_malloc (saddrlens[i]);
-#if HAVE_SOCKADDR_IN_SIN_LEN
- ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
-#endif
- ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
- ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
- }
- }
- GNUNET_free_non_null (unixpath);
- *addrs = saddrs;
- *addr_lens = saddrlens;
- return resi;
-}
-
-
-#ifdef MINGW
-/**
- * Read listen sockets from the parent process (ARM).
- *
- * @param sctx service context to initialize
- * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself),
- * and #GNUNET_SYSERR on error.
- */
-static int
-receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
-{
- const char *env_buf;
- int fail;
- uint64_t count;
- uint64_t i;
- HANDLE lsocks_pipe;
-
- env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
- if ((NULL == env_buf) || (strlen (env_buf) <= 0))
- return GNUNET_NO;
- /* Using W32 API directly here, because this pipe will
- * never be used outside of this function, and it's just too much of a bother
- * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
- */
- lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
- if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
- return GNUNET_NO;
- fail = 1;
- do
- {
- int ret;
- int fail2;
- DWORD rd;
-
- ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
- if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
- break;
- sctx->lsocks =
- GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
-
- fail2 = 1;
- for (i = 0; i < count; i++)
- {
- WSAPROTOCOL_INFOA pi;
- uint64_t size;
- SOCKET s;
-
- ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
- if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
- break;
- ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
- if ( (0 == ret) || (sizeof (pi) != rd))
- break;
- s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0,
WSA_FLAG_OVERLAPPED);
- sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
- if (NULL == sctx->lsocks[i])
- break;
- else if (i == count - 1)
- fail2 = 0;
- }
- if (fail2)
- break;
- sctx->lsocks[count] = NULL;
- fail = 0;
- }
- while (fail);
-
- CloseHandle (lsocks_pipe);
-
- if (fail)
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Could not access a pre-bound socket, will try to bind myself\n"));
- for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++)
- GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
- GNUNET_free_non_null (sctx->lsocks);
- sctx->lsocks = NULL;
- return GNUNET_NO;
- }
- return GNUNET_YES;
-}
-#endif
-
-
-/**
- * Setup addr, addrlen, idle_timeout
- * based on configuration!
- *
- * Configuration may specify:
- * - PORT (where to bind to for TCP)
- * - UNIXPATH (where to bind to for UNIX domain sockets)
- * - TIMEOUT (after how many ms does an inactive service timeout);
- * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
- * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
- * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
- * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
- * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
- * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
- *
- * @param sctx service context to initialize
- * @return #GNUNET_OK if configuration succeeded
- */
-static int
-setup_service (struct GNUNET_SERVICE_Context *sctx)
-{
- struct GNUNET_TIME_Relative idleout;
- int tolerant;
-
-#ifndef MINGW
- const char *nfds;
- unsigned int cnt;
- int flags;
-#endif
-
- if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
"TIMEOUT"))
- {
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name,
- "TIMEOUT", &idleout))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Specified value for `%s' of service `%s' is invalid\n"),
- "TIMEOUT", sctx->service_name);
- return GNUNET_SYSERR;
- }
- sctx->timeout = idleout;
- }
- else
- sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-
- if (GNUNET_CONFIGURATION_have_value
- (sctx->cfg, sctx->service_name, "TOLERANT"))
- {
- if (GNUNET_SYSERR ==
- (tolerant =
- GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
- "TOLERANT")))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Specified value for `%s' of service `%s' is invalid\n"),
- "TOLERANT", sctx->service_name);
- return GNUNET_SYSERR;
- }
- }
- else
- tolerant = GNUNET_NO;
-
-#ifndef MINGW
- errno = 0;
- if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
- (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
- (cnt + 4 < FD_SETSIZE))
- {
- sctx->lsocks =
- GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
- while (0 < cnt--)
- {
- flags = fcntl (3 + cnt, F_GETFD);
- if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
- (NULL ==
- (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _
- ("Could not access pre-bound socket %u, will try to bind
myself\n"),
- (unsigned int) 3 + cnt);
- cnt++;
- while (sctx->lsocks[cnt] != NULL)
- GNUNET_break (0 == GNUNET_NETWORK_socket_close
(sctx->lsocks[cnt++]));
- GNUNET_free (sctx->lsocks);
- sctx->lsocks = NULL;
- break;
- }
- }
- unsetenv ("LISTEN_FDS");
- }
-#else
- if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
- {
- receive_sockets_from_parent (sctx);
- putenv ("GNUNET_OS_READ_LSOCKS=");
- }
-#endif
-
- if ((NULL == sctx->lsocks) &&
- (GNUNET_SYSERR ==
- GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg,
- &sctx->addrs, &sctx->addrlens)))
- return GNUNET_SYSERR;
- sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
- sctx->match_uid =
- GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
- "UNIX_MATCH_UID");
- sctx->match_gid =
- GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
- "UNIX_MATCH_GID");
- process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
- process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
- process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
- process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
-
- return GNUNET_OK;
-}
-
-
-/**
- * Get the name of the user that'll be used
- * to provide the service.
- *
- * @param sctx service context
- * @return value of the 'USERNAME' option
- */
-static char *
-get_user_name (struct GNUNET_SERVICE_Context *sctx)
-{
- char *un;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
- "USERNAME", &un))
- return NULL;
- return un;
-}
-
-
-/**
- * Write PID file.
- *
- * @param sctx service context
- * @param pid PID to write (should be equal to 'getpid()'
- * @return #GNUNET_OK on success (including no work to be done)
- */
-static int
-write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
-{
- FILE *pidfd;
- char *pif;
- char *user;
- char *rdir;
- int len;
-
- if (NULL == (pif = get_pid_file_name (sctx)))
- return GNUNET_OK; /* no file desired */
- user = get_user_name (sctx);
- rdir = GNUNET_strdup (pif);
- len = strlen (rdir);
- while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
- len--;
- rdir[len] = '\0';
- if (0 != ACCESS (rdir, F_OK))
- {
- /* we get to create a directory -- and claim it
- * as ours! */
- (void) GNUNET_DISK_directory_create (rdir);
- if ((NULL != user) && (0 < strlen (user)))
- GNUNET_DISK_file_change_owner (rdir, user);
- }
- if (0 != ACCESS (rdir, W_OK | X_OK))
- {
- LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
- GNUNET_free (rdir);
- GNUNET_free_non_null (user);
- GNUNET_free (pif);
- return GNUNET_SYSERR;
- }
- GNUNET_free (rdir);
- pidfd = FOPEN (pif, "w");
- if (NULL == pidfd)
- {
- LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
- GNUNET_free (pif);
- GNUNET_free_non_null (user);
- return GNUNET_SYSERR;
- }
- if (0 > FPRINTF (pidfd, "%u", pid))
- LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
- GNUNET_break (0 == FCLOSE (pidfd));
- if ((NULL != user) && (0 < strlen (user)))
- GNUNET_DISK_file_change_owner (pif, user);
- GNUNET_free_non_null (user);
- GNUNET_free (pif);
- return GNUNET_OK;
-}
-
-
-/**
- * Task run during shutdown. Stops the server/service.
- *
- * @param cls the `struct GNUNET_SERVICE_Context`
- */
-static void
-shutdown_task (void *cls)
-{
- struct GNUNET_SERVICE_Context *service = cls;
- struct GNUNET_SERVER_Handle *server = service->server;
-
- service->shutdown_task = NULL;
- if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN))
- GNUNET_SERVER_stop_listening (server);
- else
- GNUNET_SERVER_destroy (server);
-}
-
-
-/**
- * Initial task for the service.
- *
- * @param cls service context
- */
-static void
-service_task (void *cls)
-{
- struct GNUNET_SERVICE_Context *sctx = cls;
- unsigned int i;
-
- (void) GNUNET_SPEEDUP_start_ (sctx->cfg);
- GNUNET_RESOLVER_connect (sctx->cfg);
- if (NULL != sctx->lsocks)
- sctx->server
- = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
- sctx->timeout, sctx->require_found);
- else
- sctx->server
- = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
- sctx->timeout, sctx->require_found);
- if (NULL == sctx->server)
- {
- if (NULL != sctx->addrs)
- for (i = 0; NULL != sctx->addrs[i]; i++)
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Failed to start `%s' at `%s'\n"),
- sctx->service_name, GNUNET_a2s (sctx->addrs[i],
sctx->addrlens[i]));
- sctx->ret = GNUNET_SYSERR;
- return;
- }
-#ifndef WINDOWS
- if (NULL != sctx->addrs)
- for (i = 0; NULL != sctx->addrs[i]; i++)
- if ((AF_UNIX == sctx->addrs[i]->sa_family)
- && ('\0' != ((const struct sockaddr_un
*)sctx->addrs[i])->sun_path[0]))
- GNUNET_DISK_fix_permissions (((const struct sockaddr_un
*)sctx->addrs[i])->sun_path,
- sctx->match_uid,
- sctx->match_gid);
-#endif
-
-
- if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN))
- {
- /* install a task that will kill the server
- * process if the scheduler ever gets a shutdown signal */
- sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
- sctx);
- }
- sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
- GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
- i = 0;
- while (NULL != sctx->my_handlers[i].callback)
- sctx->my_handlers[i++].callback_cls = sctx;
- GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
- if (-1 != sctx->ready_confirm_fd)
- {
- GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
- GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
- sctx->ready_confirm_fd = -1;
- write_pid_file (sctx, getpid ());
- }
- if (NULL != sctx->addrs)
- {
- i = 0;
- while (NULL != sctx->addrs[i])
- {
- LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
- sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
- i++;
- }
- }
- sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
-}
-
-
-/**
- * Detach from terminal.
- *
- * @param sctx service context
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-detach_terminal (struct GNUNET_SERVICE_Context *sctx)
-{
-#ifndef MINGW
- pid_t pid;
- int nullfd;
- int filedes[2];
-
- if (0 != PIPE (filedes))
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
- return GNUNET_SYSERR;
- }
- pid = fork ();
- if (pid < 0)
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
- return GNUNET_SYSERR;
- }
- if (0 != pid)
- {
- /* Parent */
- char c;
-
- GNUNET_break (0 == CLOSE (filedes[1]));
- c = 'X';
- if (1 != READ (filedes[0], &c, sizeof (char)))
- LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
- fflush (stdout);
- switch (c)
- {
- case '.':
- exit (0);
- case 'I':
- LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to
initialize\n"));
- break;
- case 'S':
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Service process could not initialize server function\n"));
- break;
- case 'X':
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Service process failed to report status\n"));
- break;
- }
- exit (1); /* child reported error */
- }
- GNUNET_break (0 == CLOSE (0));
- GNUNET_break (0 == CLOSE (1));
- GNUNET_break (0 == CLOSE (filedes[0]));
- nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND);
- if (nullfd < 0)
- return GNUNET_SYSERR;
- /* set stdin/stdout to /dev/null */
- if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
- (void) CLOSE (nullfd);
- return GNUNET_SYSERR;
- }
- (void) CLOSE (nullfd);
- /* Detach from controlling terminal */
- pid = setsid ();
- if (-1 == pid)
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
- sctx->ready_confirm_fd = filedes[1];
-#else
- /* FIXME: we probably need to do something else
- * elsewhere in order to fork the process itself... */
- FreeConsole ();
-#endif
- return GNUNET_OK;
-}
-
-
-/**
- * Set user ID.
- *
- * @param sctx service context
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-set_user_id (struct GNUNET_SERVICE_Context *sctx)
-{
- char *user;
-
- if (NULL == (user = get_user_name (sctx)))
- return GNUNET_OK; /* keep */
-#ifndef MINGW
- struct passwd *pws;
-
- errno = 0;
- pws = getpwnam (user);
- if (NULL == pws)
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Cannot obtain information about user `%s': %s\n"), user,
- errno == 0 ? _("No such user") : STRERROR (errno));
- GNUNET_free (user);
- return GNUNET_SYSERR;
- }
- if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
-#if HAVE_INITGROUPS
- (0 != initgroups (user, pws->pw_gid)) ||
-#endif
- (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
- {
- if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
- (0 != setreuid (pws->pw_uid, pws->pw_uid)))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s':
%s\n"),
- user, STRERROR (errno));
- GNUNET_free (user);
- return GNUNET_SYSERR;
- }
- }
-#endif
- GNUNET_free (user);
- return GNUNET_OK;
-}
-
-
-/**
- * Delete the PID file that was created by our parent.
- *
- * @param sctx service context
- */
-static void
-pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
-{
- char *pif = get_pid_file_name (sctx);
-
- if (NULL == pif)
- return; /* no PID file */
- if (0 != UNLINK (pif))
- LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
- GNUNET_free (pif);
-}
-
-
-/**
- * Run a standard GNUnet service startup sequence (initialize loggers
- * and configuration, parse options).
- *
- * @param argc number of command line arguments
- * @param argv command line arguments
- * @param service_name our service name
- * @param options service options
- * @param task main task of the service
- * @param task_cls closure for @a task
- * @return #GNUNET_SYSERR on error, #GNUNET_OK
- * if we shutdown nicely
- */
-int
-GNUNET_SERVICE_run (int argc, char *const *argv,
- const char *service_name,
- enum GNUNET_SERVICE_Options options,
- GNUNET_SERVICE_Main task,
- void *task_cls)
-{
-#define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0)
-
- int err;
- int ret;
- char *cfg_fn;
- char *opt_cfg_fn;
- char *loglev;
- char *logfile;
- int do_daemonize;
- unsigned int i;
- unsigned long long skew_offset;
- unsigned long long skew_variance;
- long long clock_offset;
- struct GNUNET_SERVICE_Context sctx;
- struct GNUNET_CONFIGURATION_Handle *cfg;
- const char *xdg;
-
- struct GNUNET_GETOPT_CommandLineOption service_options[] = {
- GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_fn),
- {'d', "daemonize", NULL,
- gettext_noop ("do daemonize (detach from terminal)"), 0,
- GNUNET_GETOPT_set_one, &do_daemonize},
- GNUNET_GETOPT_OPTION_HELP (NULL),
- GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
- GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
- GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
- GNUNET_GETOPT_OPTION_END
- };
- err = 1;
- do_daemonize = 0;
- logfile = NULL;
- loglev = NULL;
- opt_cfg_fn = NULL;
- xdg = getenv ("XDG_CONFIG_HOME");
- if (NULL != xdg)
- GNUNET_asprintf (&cfg_fn,
- "%s%s%s",
- xdg,
- DIR_SEPARATOR_STR,
- GNUNET_OS_project_data_get ()->config_file);
- else
- cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
- memset (&sctx, 0, sizeof (sctx));
- sctx.options = options;
- sctx.ready_confirm_fd = -1;
- sctx.ret = GNUNET_OK;
- sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
- sctx.task = task;
- sctx.task_cls = task_cls;
- sctx.service_name = service_name;
- sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
-
- /* setup subsystems */
- ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
- if (GNUNET_SYSERR == ret)
- goto shutdown;
- if (GNUNET_NO == ret)
- {
- err = 0;
- goto shutdown;
- }
- if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
- HANDLE_ERROR;
- if (NULL == opt_cfg_fn)
- opt_cfg_fn = GNUNET_strdup (cfg_fn);
- if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
- {
- if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Malformed configuration file `%s', exit ...\n"),
- opt_cfg_fn);
- goto shutdown;
- }
- }
- else
- {
- if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Malformed configuration, exit ...\n"));
- goto shutdown;
- }
- if (0 != strcmp (opt_cfg_fn, cfg_fn))
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Could not access configuration file `%s'\n"),
- opt_cfg_fn);
- }
- if (GNUNET_OK != setup_service (&sctx))
- goto shutdown;
- if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
- HANDLE_ERROR;
- if (GNUNET_OK != set_user_id (&sctx))
- goto shutdown;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Service `%s' runs with configuration from `%s'\n",
- service_name,
- opt_cfg_fn);
- if ((GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
- "SKEW_OFFSET", &skew_offset)) &&
- (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
- "SKEW_VARIANCE",
&skew_variance)))
- {
- clock_offset = skew_offset - skew_variance;
- GNUNET_TIME_set_offset (clock_offset);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
- }
- /* actually run service */
- err = 0;
- GNUNET_SCHEDULER_run (&service_task, &sctx);
- /* shutdown */
- if ((1 == do_daemonize) && (NULL != sctx.server))
- pid_file_delete (&sctx);
- GNUNET_free_non_null (sctx.my_handlers);
-
-shutdown:
- if (-1 != sctx.ready_confirm_fd)
- {
- if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
- LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
- GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
- }
-#if HAVE_MALLINFO
- {
- char *counter;
-
- if ( (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name,
- "GAUGER_HEAP")) &&
- (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name,
- "GAUGER_HEAP",
- &counter)) )
- {
- struct mallinfo mi;
-
- mi = mallinfo ();
- GAUGER (service_name, counter, mi.usmblks, "blocks");
- GNUNET_free (counter);
- }
- }
-#endif
- GNUNET_SPEEDUP_stop_ ();
- GNUNET_CONFIGURATION_destroy (cfg);
- i = 0;
- if (NULL != sctx.addrs)
- while (NULL != sctx.addrs[i])
- GNUNET_free (sctx.addrs[i++]);
- GNUNET_free_non_null (sctx.addrs);
- GNUNET_free_non_null (sctx.addrlens);
- GNUNET_free_non_null (logfile);
- GNUNET_free_non_null (loglev);
- GNUNET_free (cfg_fn);
- GNUNET_free_non_null (opt_cfg_fn);
- GNUNET_free_non_null (sctx.v4_denied);
- GNUNET_free_non_null (sctx.v6_denied);
- GNUNET_free_non_null (sctx.v4_allowed);
- GNUNET_free_non_null (sctx.v6_allowed);
-
- return err ? GNUNET_SYSERR : sctx.ret;
-}
-
-
-/**
- * Run a service startup sequence within an existing
- * initialized system.
- *
- * @param service_name our service name
- * @param cfg configuration to use
- * @param options service options
- * @return NULL on error, service handle
- */
-struct GNUNET_SERVICE_Context *
-GNUNET_SERVICE_start (const char *service_name,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- enum GNUNET_SERVICE_Options options)
-{
- int i;
- struct GNUNET_SERVICE_Context *sctx;
-
- sctx = GNUNET_new (struct GNUNET_SERVICE_Context);
- sctx->ready_confirm_fd = -1; /* no daemonizing */
- sctx->ret = GNUNET_OK;
- sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
- sctx->service_name = service_name;
- sctx->cfg = cfg;
- sctx->options = options;
-
- /* setup subsystems */
- if (GNUNET_OK != setup_service (sctx))
- {
- GNUNET_SERVICE_stop (sctx);
- return NULL;
- }
- if (NULL != sctx->lsocks)
- sctx->server =
- GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
- sctx->timeout, sctx->require_found);
- else
- sctx->server =
- GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
- sctx->timeout, sctx->require_found);
-
- if (NULL == sctx->server)
- {
- GNUNET_SERVICE_stop (sctx);
- return NULL;
- }
-#ifndef WINDOWS
- if (NULL != sctx->addrs)
- for (i = 0; NULL != sctx->addrs[i]; i++)
- if ((AF_UNIX == sctx->addrs[i]->sa_family)
- && ('\0' != ((const struct sockaddr_un
*)sctx->addrs[i])->sun_path[0]))
- GNUNET_DISK_fix_permissions (((const struct sockaddr_un
*)sctx->addrs[i])->sun_path,
- sctx->match_uid,
- sctx->match_gid);
-#endif
- sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
- GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
- i = 0;
- while ((sctx->my_handlers[i].callback != NULL))
- sctx->my_handlers[i++].callback_cls = sctx;
- GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
- return sctx;
-}
-
-
-/**
- * Obtain the server used by a service. Note that the server must NOT
- * be destroyed by the caller.
- *
- * @param ctx the service context returned from the start function
- * @return handle to the server for this service, NULL if there is none
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx)
-{
- return ctx->server;
-}
-
-
-/**
- * Get the NULL-terminated array of listen sockets for this service.
- *
- * @param ctx service context to query
- * @return NULL if there are no listen sockets, otherwise NULL-terminated
- * array of listen sockets.
- */
-struct GNUNET_NETWORK_Handle *const*
-GNUNET_SERVICE_get_listen_sockets (struct GNUNET_SERVICE_Context *ctx)
-{
- return ctx->lsocks;
-}
-
-
-/**
- * Stop a service that was started with "GNUNET_SERVICE_start".
- *
- * @param sctx the service context returned from the start function
- */
-void
-GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx)
-{
- unsigned int i;
-
-#if HAVE_MALLINFO
- {
- char *counter;
-
- if ( (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
- "GAUGER_HEAP")) &&
- (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name,
- "GAUGER_HEAP",
- &counter)) )
- {
- struct mallinfo mi;
-
- mi = mallinfo ();
- GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
- GNUNET_free (counter);
- }
- }
-#endif
- if (NULL != sctx->shutdown_task)
- {
- GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
- sctx->shutdown_task = NULL;
- }
- if (NULL != sctx->server)
- GNUNET_SERVER_destroy (sctx->server);
- GNUNET_free_non_null (sctx->my_handlers);
- if (NULL != sctx->addrs)
- {
- i = 0;
- while (NULL != sctx->addrs[i])
- GNUNET_free (sctx->addrs[i++]);
- GNUNET_free (sctx->addrs);
- }
- GNUNET_free_non_null (sctx->addrlens);
- GNUNET_free_non_null (sctx->v4_denied);
- GNUNET_free_non_null (sctx->v6_denied);
- GNUNET_free_non_null (sctx->v4_allowed);
- GNUNET_free_non_null (sctx->v6_allowed);
- GNUNET_free (sctx);
-}
-
-
-/* end of service.c */
Added: gnunet/src/util/service.c
===================================================================
--- gnunet/src/util/service.c (rev 0)
+++ gnunet/src/util/service.c 2016-10-23 16:03:54 UTC (rev 38186)
@@ -0,0 +1,1697 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2009, 2012 GNUnet e.V.
+
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file util/service.c
+ * @brief functions related to starting services
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_constants.h"
+#include "gnunet_resolver_service.h"
+#include "speedup.h"
+
+#if HAVE_MALLINFO
+#include <malloc.h>
+#include "gauger.h"
+#endif
+
+
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util",
syscall)
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file
(kind, "util", syscall, filename)
+
+
+/* ******************* access control ******************** */
+
+/**
+ * Check if the given IP address is in the list of IP addresses.
+ *
+ * @param list a list of networks
+ * @param add the IP to check (in network byte order)
+ * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
+ */
+static int
+check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
+ const struct in_addr *add)
+{
+ unsigned int i;
+
+ if (NULL == list)
+ return GNUNET_NO;
+ i = 0;
+ while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
+ {
+ if ((add->s_addr & list[i].netmask.s_addr) ==
+ (list[i].network.s_addr & list[i].netmask.s_addr))
+ return GNUNET_YES;
+ i++;
+ }
+ return GNUNET_NO;
+}
+
+
+/**
+ * Check if the given IP address is in the list of IP addresses.
+ *
+ * @param list a list of networks
+ * @param ip the IP to check (in network byte order)
+ * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
+ */
+static int
+check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
+ const struct in6_addr *ip)
+{
+ unsigned int i;
+ unsigned int j;
+ struct in6_addr zero;
+
+ if (NULL == list)
+ return GNUNET_NO;
+ memset (&zero, 0, sizeof (struct in6_addr));
+ i = 0;
+NEXT:
+ while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr)))
+ {
+ for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
+ if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
+ (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
+ {
+ i++;
+ goto NEXT;
+ }
+ return GNUNET_YES;
+ }
+ return GNUNET_NO;
+}
+
+
+/* ****************** service struct ****************** */
+
+
+/**
+ * Context for "service_task".
+ */
+struct GNUNET_SERVICE_Context
+{
+ /**
+ * Our configuration.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Handle for the server.
+ */
+ struct GNUNET_SERVER_Handle *server;
+
+ /**
+ * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
+ * listen sockets.
+ */
+ struct sockaddr **addrs;
+
+ /**
+ * Name of our service.
+ */
+ const char *service_name;
+
+ /**
+ * Main service-specific task to run.
+ */
+ GNUNET_SERVICE_Main task;
+
+ /**
+ * Closure for @e task.
+ */
+ void *task_cls;
+
+ /**
+ * IPv4 addresses that are not allowed to connect.
+ */
+ struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
+
+ /**
+ * IPv6 addresses that are not allowed to connect.
+ */
+ struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
+
+ /**
+ * IPv4 addresses that are allowed to connect (if not
+ * set, all are allowed).
+ */
+ struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
+
+ /**
+ * IPv6 addresses that are allowed to connect (if not
+ * set, all are allowed).
+ */
+ struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
+
+ /**
+ * My (default) message handlers. Adjusted copy
+ * of "defhandlers".
+ */
+ struct GNUNET_SERVER_MessageHandler *my_handlers;
+
+ /**
+ * Array of the lengths of the entries in addrs.
+ */
+ socklen_t *addrlens;
+
+ /**
+ * NULL-terminated array of listen sockets we should take over.
+ */
+ struct GNUNET_NETWORK_Handle **lsocks;
+
+ /**
+ * Task ID of the shutdown task.
+ */
+ struct GNUNET_SCHEDULER_Task *shutdown_task;
+
+ /**
+ * Idle timeout for server.
+ */
+ struct GNUNET_TIME_Relative timeout;
+
+ /**
+ * Overall success/failure of the service start.
+ */
+ int ret;
+
+ /**
+ * If we are daemonizing, this FD is set to the
+ * pipe to the parent. Send '.' if we started
+ * ok, '!' if not. -1 if we are not daemonizing.
+ */
+ int ready_confirm_fd;
+
+ /**
+ * Do we close connections if we receive messages
+ * for which we have no handler?
+ */
+ int require_found;
+
+ /**
+ * Do we require a matching UID for UNIX domain socket connections?
+ * #GNUNET_NO means that the UID does not have to match (however,
+ * @e match_gid may still impose other access control checks).
+ */
+ int match_uid;
+
+ /**
+ * Do we require a matching GID for UNIX domain socket connections?
+ * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
+ * checking that the client's UID is in our group OR that the
+ * client's GID is our GID. If both "match_gid" and @e match_uid are
+ * #GNUNET_NO, all users on the local system have access.
+ */
+ int match_gid;
+
+ /**
+ * Our options.
+ */
+ enum GNUNET_SERVICE_Options options;
+
+};
+
+
+/* ****************** message handlers ****************** */
+
+/**
+ * Send a 'TEST' message back to the client.
+ *
+ * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
+ * @param size number of bytes available in 'buf'
+ * @param buf where to copy the message
+ * @return number of bytes written to 'buf'
+ */
+static size_t
+write_test (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_SERVER_Client *client = cls;
+ struct GNUNET_MessageHeader *msg;
+
+ if (size < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return 0; /* client disconnected */
+ }
+ msg = (struct GNUNET_MessageHeader *) buf;
+ msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
+ msg->size = htons (sizeof (struct GNUNET_MessageHeader));
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return sizeof (struct GNUNET_MessageHeader);
+}
+
+
+/**
+ * Handler for TEST message.
+ *
+ * @param cls closure (refers to service)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_test (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ /* simply bounce message back to acknowledge */
+ if (NULL ==
+ GNUNET_SERVER_notify_transmit_ready (client,
+ sizeof (struct
GNUNET_MessageHeader),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &write_test, client))
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+}
+
+
+/**
+ * Default handlers for all services. Will be copied and the
+ * "callback_cls" fields will be replaced with the specific service
+ * struct.
+ */
+static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
+ {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
+ sizeof (struct GNUNET_MessageHeader)},
+ {NULL, NULL, 0, 0}
+};
+
+
+/* ****************** service core routines ************** */
+
+
+/**
+ * Check if access to the service is allowed from the given address.
+ *
+ * @param cls closure
+ * @param uc credentials, if available, otherwise NULL
+ * @param addr address
+ * @param addrlen length of address
+ * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR
+ * for unknown address family (will be denied).
+ */
+static int
+check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
+ const struct sockaddr *addr, socklen_t addrlen)
+{
+ struct GNUNET_SERVICE_Context *sctx = cls;
+ const struct sockaddr_in *i4;
+ const struct sockaddr_in6 *i6;
+ int ret;
+
+ switch (addr->sa_family)
+ {
+ case AF_INET:
+ GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
+ i4 = (const struct sockaddr_in *) addr;
+ ret = ((NULL == sctx->v4_allowed) ||
+ (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
+ ((NULL == sctx->v4_denied) ||
+ (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
+ break;
+ case AF_INET6:
+ GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
+ i6 = (const struct sockaddr_in6 *) addr;
+ ret = ((NULL == sctx->v6_allowed) ||
+ (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
+ ((NULL == sctx->v6_denied) ||
+ (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
+ break;
+#ifndef WINDOWS
+ case AF_UNIX:
+ ret = GNUNET_OK; /* controlled using file-system ACL now */
+ break;
+#endif
+ default:
+ LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
+ addr->sa_family);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK != ret)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Access from `%s' denied to service `%s'\n"),
+ GNUNET_a2s (addr, addrlen),
+ sctx->service_name);
+ }
+ return ret;
+}
+
+
+/**
+ * Get the name of the file where we will
+ * write the PID of the service.
+ *
+ * @param sctx service context
+ * @return name of the file for the process ID
+ */
+static char *
+get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
+{
+ char *pif;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
+ "PIDFILE", &pif))
+ return NULL;
+ return pif;
+}
+
+
+/**
+ * Parse an IPv4 access control list.
+ *
+ * @param ret location where to write the ACL (set)
+ * @param sctx service context to use to get the configuration
+ * @param option name of the ACL option to parse
+ * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
+ * no ACL configured)
+ */
+static int
+process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
+ struct GNUNET_SERVICE_Context *sctx,
+ const char *option)
+{
+ char *opt;
+
+ if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
+ {
+ *ret = NULL;
+ return GNUNET_OK;
+ }
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
+ sctx->service_name,
+ option, &opt));
+ if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
+ opt, sctx->service_name, option);
+ GNUNET_free (opt);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (opt);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Parse an IPv6 access control list.
+ *
+ * @param ret location where to write the ACL (set)
+ * @param sctx service context to use to get the configuration
+ * @param option name of the ACL option to parse
+ * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
+ * no ACL configured)
+ */
+static int
+process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
+ struct GNUNET_SERVICE_Context *sctx,
+ const char *option)
+{
+ char *opt;
+
+ if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
+ {
+ *ret = NULL;
+ return GNUNET_OK;
+ }
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
+ sctx->service_name,
+ option, &opt));
+ if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
+ opt, sctx->service_name, option);
+ GNUNET_free (opt);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (opt);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Add the given UNIX domain path as an address to the
+ * list (as the first entry).
+ *
+ * @param saddrs array to update
+ * @param saddrlens where to store the address length
+ * @param unixpath path to add
+ * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
+ * parameter is ignore on systems other than LINUX
+ */
+static void
+add_unixpath (struct sockaddr **saddrs,
+ socklen_t *saddrlens,
+ const char *unixpath,
+ int abstract)
+{
+#ifdef AF_UNIX
+ struct sockaddr_un *un;
+
+ un = GNUNET_new (struct sockaddr_un);
+ un->sun_family = AF_UNIX;
+ strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
+#ifdef LINUX
+ if (GNUNET_YES == abstract)
+ un->sun_path[0] = '\0';
+#endif
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ un->sun_len = (u_char) sizeof (struct sockaddr_un);
+#endif
+ *saddrs = (struct sockaddr *) un;
+ *saddrlens = sizeof (struct sockaddr_un);
+#else
+ /* this function should never be called
+ * unless AF_UNIX is defined! */
+ GNUNET_assert (0);
+#endif
+}
+
+
+/**
+ * Get the list of addresses that a server for the given service
+ * should bind to.
+ *
+ * @param service_name name of the service
+ * @param cfg configuration (which specifies the addresses)
+ * @param addrs set (call by reference) to an array of pointers to the
+ * addresses the server should bind to and listen on; the
+ * array will be NULL-terminated (on success)
+ * @param addr_lens set (call by reference) to an array of the lengths
+ * of the respective `struct sockaddr` struct in the @a addrs
+ * array (on success)
+ * @return number of addresses found on success,
+ * #GNUNET_SYSERR if the configuration
+ * did not specify reasonable finding information or
+ * if it specified a hostname that could not be resolved;
+ * #GNUNET_NO if the number of addresses configured is
+ * zero (in this case, `*addrs` and `*addr_lens` will be
+ * set to NULL).
+ */
+int
+GNUNET_SERVICE_get_server_addresses (const char *service_name,
+ const struct GNUNET_CONFIGURATION_Handle
*cfg,
+ struct sockaddr ***addrs,
+ socklen_t ** addr_lens)
+{
+ int disablev6;
+ struct GNUNET_NETWORK_Handle *desc;
+ unsigned long long port;
+ char *unixpath;
+ struct addrinfo hints;
+ struct addrinfo *res;
+ struct addrinfo *pos;
+ struct addrinfo *next;
+ unsigned int i;
+ int resi;
+ int ret;
+ int abstract;
+ struct sockaddr **saddrs;
+ socklen_t *saddrlens;
+ char *hostname;
+
+ *addrs = NULL;
+ *addr_lens = NULL;
+ desc = NULL;
+ if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
+ {
+ if (GNUNET_SYSERR ==
+ (disablev6 =
+ GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name,
"DISABLEV6")))
+ return GNUNET_SYSERR;
+ }
+ else
+ disablev6 = GNUNET_NO;
+
+ if (! disablev6)
+ {
+ /* probe IPv6 support */
+ desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
+ if (NULL == desc)
+ {
+ if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
+ (EACCES == errno))
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+ return GNUNET_SYSERR;
+ }
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Disabling IPv6 support for service `%s', failed to create IPv6
socket: %s\n"),
+ service_name, STRERROR (errno));
+ disablev6 = GNUNET_YES;
+ }
+ else
+ {
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+ desc = NULL;
+ }
+ }
+
+ port = 0;
+ if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
+ {
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
+ "PORT", &port))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Require valid port number for service `%s' in configuration!\n"),
+ service_name);
+ }
+ if (port > 65535)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Require valid port number for service `%s' in configuration!\n"),
+ service_name);
+ return GNUNET_SYSERR;
+ }
+ }
+
+ if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
+ {
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
+ "BINDTO", &hostname));
+ }
+ else
+ hostname = NULL;
+
+ unixpath = NULL;
+ abstract = GNUNET_NO;
+#ifdef AF_UNIX
+ if ((GNUNET_YES ==
+ GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
+ (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
+ &unixpath)) &&
+ (0 < strlen (unixpath)))
+ {
+ /* probe UNIX support */
+ struct sockaddr_un s_un;
+
+ if (strlen (unixpath) >= sizeof (s_un.sun_path))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
+ (unsigned long long) sizeof (s_un.sun_path));
+ unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Using `%s' instead\n"),
+ unixpath);
+ }
+#ifdef LINUX
+ abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
+ "TESTING",
+ "USE_ABSTRACT_SOCKETS");
+ if (GNUNET_SYSERR == abstract)
+ abstract = GNUNET_NO;
+#endif
+ if ((GNUNET_YES != abstract)
+ && (GNUNET_OK !=
+ GNUNET_DISK_directory_create_for_file (unixpath)))
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "mkdir",
+ unixpath);
+ }
+ if (NULL != unixpath)
+ {
+ desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
+ if (NULL == desc)
+ {
+ if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
+ (EACCES == errno))
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+ GNUNET_free_non_null (hostname);
+ GNUNET_free (unixpath);
+ return GNUNET_SYSERR;
+ }
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Disabling UNIX domain socket support for service `%s', failed to
create UNIX domain socket: %s\n"),
+ service_name,
+ STRERROR (errno));
+ GNUNET_free (unixpath);
+ unixpath = NULL;
+ }
+ else
+ {
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+ desc = NULL;
+ }
+ }
+#endif
+
+ if ((0 == port) && (NULL == unixpath))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Have neither PORT nor UNIXPATH for service `%s', but one is
required\n"),
+ service_name);
+ GNUNET_free_non_null (hostname);
+ return GNUNET_SYSERR;
+ }
+ if (0 == port)
+ {
+ saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
+ saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
+ add_unixpath (saddrs, saddrlens, unixpath, abstract);
+ GNUNET_free_non_null (unixpath);
+ GNUNET_free_non_null (hostname);
+ *addrs = saddrs;
+ *addr_lens = saddrlens;
+ return 1;
+ }
+
+ if (NULL != hostname)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Resolving `%s' since that is where `%s' will bind to.\n",
+ hostname,
+ service_name);
+ memset (&hints, 0, sizeof (struct addrinfo));
+ if (disablev6)
+ hints.ai_family = AF_INET;
+ hints.ai_protocol = IPPROTO_TCP;
+ if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
+ (NULL == res))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to resolve `%s': %s\n"),
+ hostname,
+ gai_strerror (ret));
+ GNUNET_free (hostname);
+ GNUNET_free_non_null (unixpath);
+ return GNUNET_SYSERR;
+ }
+ next = res;
+ i = 0;
+ while (NULL != (pos = next))
+ {
+ next = pos->ai_next;
+ if ((disablev6) && (pos->ai_family == AF_INET6))
+ continue;
+ i++;
+ }
+ if (0 == i)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to find %saddress for `%s'.\n"),
+ disablev6 ? "IPv4 " : "",
+ hostname);
+ freeaddrinfo (res);
+ GNUNET_free (hostname);
+ GNUNET_free_non_null (unixpath);
+ return GNUNET_SYSERR;
+ }
+ resi = i;
+ if (NULL != unixpath)
+ resi++;
+ saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+ saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+ i = 0;
+ if (NULL != unixpath)
+ {
+ add_unixpath (saddrs, saddrlens, unixpath, abstract);
+ i++;
+ }
+ next = res;
+ while (NULL != (pos = next))
+ {
+ next = pos->ai_next;
+ if ((disablev6) && (AF_INET6 == pos->ai_family))
+ continue;
+ if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
+ continue; /* not TCP */
+ if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
+ continue; /* huh? */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
+ service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
+ if (AF_INET == pos->ai_family)
+ {
+ GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
+ saddrlens[i] = pos->ai_addrlen;
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+ GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+ ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+ }
+ else
+ {
+ GNUNET_assert (AF_INET6 == pos->ai_family);
+ GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
+ saddrlens[i] = pos->ai_addrlen;
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+ GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+ ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
+ }
+ i++;
+ }
+ GNUNET_free (hostname);
+ freeaddrinfo (res);
+ resi = i;
+ }
+ else
+ {
+ /* will bind against everything, just set port */
+ if (disablev6)
+ {
+ /* V4-only */
+ resi = 1;
+ if (NULL != unixpath)
+ resi++;
+ i = 0;
+ saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+ saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+ if (NULL != unixpath)
+ {
+ add_unixpath (saddrs, saddrlens, unixpath, abstract);
+ i++;
+ }
+ saddrlens[i] = sizeof (struct sockaddr_in);
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
+#endif
+ ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
+ ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+ }
+ else
+ {
+ /* dual stack */
+ resi = 2;
+ if (NULL != unixpath)
+ resi++;
+ saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+ saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+ i = 0;
+ if (NULL != unixpath)
+ {
+ add_unixpath (saddrs, saddrlens, unixpath, abstract);
+ i++;
+ }
+ saddrlens[i] = sizeof (struct sockaddr_in6);
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
+#endif
+ ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
+ ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
+ i++;
+ saddrlens[i] = sizeof (struct sockaddr_in);
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
+#endif
+ ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
+ ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+ }
+ }
+ GNUNET_free_non_null (unixpath);
+ *addrs = saddrs;
+ *addr_lens = saddrlens;
+ return resi;
+}
+
+
+#ifdef MINGW
+/**
+ * Read listen sockets from the parent process (ARM).
+ *
+ * @param sctx service context to initialize
+ * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself),
+ * and #GNUNET_SYSERR on error.
+ */
+static int
+receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
+{
+ const char *env_buf;
+ int fail;
+ uint64_t count;
+ uint64_t i;
+ HANDLE lsocks_pipe;
+
+ env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
+ if ((NULL == env_buf) || (strlen (env_buf) <= 0))
+ return GNUNET_NO;
+ /* Using W32 API directly here, because this pipe will
+ * never be used outside of this function, and it's just too much of a bother
+ * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
+ */
+ lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
+ if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
+ return GNUNET_NO;
+ fail = 1;
+ do
+ {
+ int ret;
+ int fail2;
+ DWORD rd;
+
+ ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
+ if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
+ break;
+ sctx->lsocks =
+ GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
+
+ fail2 = 1;
+ for (i = 0; i < count; i++)
+ {
+ WSAPROTOCOL_INFOA pi;
+ uint64_t size;
+ SOCKET s;
+
+ ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
+ if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
+ break;
+ ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
+ if ( (0 == ret) || (sizeof (pi) != rd))
+ break;
+ s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0,
WSA_FLAG_OVERLAPPED);
+ sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
+ if (NULL == sctx->lsocks[i])
+ break;
+ else if (i == count - 1)
+ fail2 = 0;
+ }
+ if (fail2)
+ break;
+ sctx->lsocks[count] = NULL;
+ fail = 0;
+ }
+ while (fail);
+
+ CloseHandle (lsocks_pipe);
+
+ if (fail)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not access a pre-bound socket, will try to bind myself\n"));
+ for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++)
+ GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
+ GNUNET_free_non_null (sctx->lsocks);
+ sctx->lsocks = NULL;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+#endif
+
+
+/**
+ * Setup addr, addrlen, idle_timeout
+ * based on configuration!
+ *
+ * Configuration may specify:
+ * - PORT (where to bind to for TCP)
+ * - UNIXPATH (where to bind to for UNIX domain sockets)
+ * - TIMEOUT (after how many ms does an inactive service timeout);
+ * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
+ * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
+ * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
+ * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
+ * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
+ * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
+ *
+ * @param sctx service context to initialize
+ * @return #GNUNET_OK if configuration succeeded
+ */
+static int
+setup_service (struct GNUNET_SERVICE_Context *sctx)
+{
+ struct GNUNET_TIME_Relative idleout;
+ int tolerant;
+
+#ifndef MINGW
+ const char *nfds;
+ unsigned int cnt;
+ int flags;
+#endif
+
+ if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
"TIMEOUT"))
+ {
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name,
+ "TIMEOUT", &idleout))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Specified value for `%s' of service `%s' is invalid\n"),
+ "TIMEOUT", sctx->service_name);
+ return GNUNET_SYSERR;
+ }
+ sctx->timeout = idleout;
+ }
+ else
+ sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+
+ if (GNUNET_CONFIGURATION_have_value
+ (sctx->cfg, sctx->service_name, "TOLERANT"))
+ {
+ if (GNUNET_SYSERR ==
+ (tolerant =
+ GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+ "TOLERANT")))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Specified value for `%s' of service `%s' is invalid\n"),
+ "TOLERANT", sctx->service_name);
+ return GNUNET_SYSERR;
+ }
+ }
+ else
+ tolerant = GNUNET_NO;
+
+#ifndef MINGW
+ errno = 0;
+ if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
+ (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
+ (cnt + 4 < FD_SETSIZE))
+ {
+ sctx->lsocks =
+ GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
+ while (0 < cnt--)
+ {
+ flags = fcntl (3 + cnt, F_GETFD);
+ if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
+ (NULL ==
+ (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _
+ ("Could not access pre-bound socket %u, will try to bind
myself\n"),
+ (unsigned int) 3 + cnt);
+ cnt++;
+ while (sctx->lsocks[cnt] != NULL)
+ GNUNET_break (0 == GNUNET_NETWORK_socket_close
(sctx->lsocks[cnt++]));
+ GNUNET_free (sctx->lsocks);
+ sctx->lsocks = NULL;
+ break;
+ }
+ }
+ unsetenv ("LISTEN_FDS");
+ }
+#else
+ if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
+ {
+ receive_sockets_from_parent (sctx);
+ putenv ("GNUNET_OS_READ_LSOCKS=");
+ }
+#endif
+
+ if ((NULL == sctx->lsocks) &&
+ (GNUNET_SYSERR ==
+ GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg,
+ &sctx->addrs, &sctx->addrlens)))
+ return GNUNET_SYSERR;
+ sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
+ sctx->match_uid =
+ GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+ "UNIX_MATCH_UID");
+ sctx->match_gid =
+ GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+ "UNIX_MATCH_GID");
+ process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
+ process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
+ process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
+ process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Get the name of the user that'll be used
+ * to provide the service.
+ *
+ * @param sctx service context
+ * @return value of the 'USERNAME' option
+ */
+static char *
+get_user_name (struct GNUNET_SERVICE_Context *sctx)
+{
+ char *un;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
+ "USERNAME", &un))
+ return NULL;
+ return un;
+}
+
+
+/**
+ * Write PID file.
+ *
+ * @param sctx service context
+ * @param pid PID to write (should be equal to 'getpid()'
+ * @return #GNUNET_OK on success (including no work to be done)
+ */
+static int
+write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
+{
+ FILE *pidfd;
+ char *pif;
+ char *user;
+ char *rdir;
+ int len;
+
+ if (NULL == (pif = get_pid_file_name (sctx)))
+ return GNUNET_OK; /* no file desired */
+ user = get_user_name (sctx);
+ rdir = GNUNET_strdup (pif);
+ len = strlen (rdir);
+ while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
+ len--;
+ rdir[len] = '\0';
+ if (0 != ACCESS (rdir, F_OK))
+ {
+ /* we get to create a directory -- and claim it
+ * as ours! */
+ (void) GNUNET_DISK_directory_create (rdir);
+ if ((NULL != user) && (0 < strlen (user)))
+ GNUNET_DISK_file_change_owner (rdir, user);
+ }
+ if (0 != ACCESS (rdir, W_OK | X_OK))
+ {
+ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
+ GNUNET_free (rdir);
+ GNUNET_free_non_null (user);
+ GNUNET_free (pif);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (rdir);
+ pidfd = FOPEN (pif, "w");
+ if (NULL == pidfd)
+ {
+ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
+ GNUNET_free (pif);
+ GNUNET_free_non_null (user);
+ return GNUNET_SYSERR;
+ }
+ if (0 > FPRINTF (pidfd, "%u", pid))
+ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
+ GNUNET_break (0 == FCLOSE (pidfd));
+ if ((NULL != user) && (0 < strlen (user)))
+ GNUNET_DISK_file_change_owner (pif, user);
+ GNUNET_free_non_null (user);
+ GNUNET_free (pif);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Task run during shutdown. Stops the server/service.
+ *
+ * @param cls the `struct GNUNET_SERVICE_Context`
+ */
+static void
+shutdown_task (void *cls)
+{
+ struct GNUNET_SERVICE_Context *service = cls;
+ struct GNUNET_SERVER_Handle *server = service->server;
+
+ service->shutdown_task = NULL;
+ if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN))
+ GNUNET_SERVER_stop_listening (server);
+ else
+ GNUNET_SERVER_destroy (server);
+}
+
+
+/**
+ * Initial task for the service.
+ *
+ * @param cls service context
+ */
+static void
+service_task (void *cls)
+{
+ struct GNUNET_SERVICE_Context *sctx = cls;
+ unsigned int i;
+
+ (void) GNUNET_SPEEDUP_start_ (sctx->cfg);
+ GNUNET_RESOLVER_connect (sctx->cfg);
+ if (NULL != sctx->lsocks)
+ sctx->server
+ = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
+ sctx->timeout, sctx->require_found);
+ else
+ sctx->server
+ = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
+ sctx->timeout, sctx->require_found);
+ if (NULL == sctx->server)
+ {
+ if (NULL != sctx->addrs)
+ for (i = 0; NULL != sctx->addrs[i]; i++)
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Failed to start `%s' at `%s'\n"),
+ sctx->service_name, GNUNET_a2s (sctx->addrs[i],
sctx->addrlens[i]));
+ sctx->ret = GNUNET_SYSERR;
+ return;
+ }
+#ifndef WINDOWS
+ if (NULL != sctx->addrs)
+ for (i = 0; NULL != sctx->addrs[i]; i++)
+ if ((AF_UNIX == sctx->addrs[i]->sa_family)
+ && ('\0' != ((const struct sockaddr_un
*)sctx->addrs[i])->sun_path[0]))
+ GNUNET_DISK_fix_permissions (((const struct sockaddr_un
*)sctx->addrs[i])->sun_path,
+ sctx->match_uid,
+ sctx->match_gid);
+#endif
+
+
+ if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN))
+ {
+ /* install a task that will kill the server
+ * process if the scheduler ever gets a shutdown signal */
+ sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+ sctx);
+ }
+ sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
+ GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
+ i = 0;
+ while (NULL != sctx->my_handlers[i].callback)
+ sctx->my_handlers[i++].callback_cls = sctx;
+ GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
+ if (-1 != sctx->ready_confirm_fd)
+ {
+ GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
+ GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
+ sctx->ready_confirm_fd = -1;
+ write_pid_file (sctx, getpid ());
+ }
+ if (NULL != sctx->addrs)
+ {
+ i = 0;
+ while (NULL != sctx->addrs[i])
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
+ sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
+ i++;
+ }
+ }
+ sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
+}
+
+
+/**
+ * Detach from terminal.
+ *
+ * @param sctx service context
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+detach_terminal (struct GNUNET_SERVICE_Context *sctx)
+{
+#ifndef MINGW
+ pid_t pid;
+ int nullfd;
+ int filedes[2];
+
+ if (0 != PIPE (filedes))
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
+ return GNUNET_SYSERR;
+ }
+ pid = fork ();
+ if (pid < 0)
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
+ return GNUNET_SYSERR;
+ }
+ if (0 != pid)
+ {
+ /* Parent */
+ char c;
+
+ GNUNET_break (0 == CLOSE (filedes[1]));
+ c = 'X';
+ if (1 != READ (filedes[0], &c, sizeof (char)))
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
+ fflush (stdout);
+ switch (c)
+ {
+ case '.':
+ exit (0);
+ case 'I':
+ LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to
initialize\n"));
+ break;
+ case 'S':
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Service process could not initialize server function\n"));
+ break;
+ case 'X':
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Service process failed to report status\n"));
+ break;
+ }
+ exit (1); /* child reported error */
+ }
+ GNUNET_break (0 == CLOSE (0));
+ GNUNET_break (0 == CLOSE (1));
+ GNUNET_break (0 == CLOSE (filedes[0]));
+ nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND);
+ if (nullfd < 0)
+ return GNUNET_SYSERR;
+ /* set stdin/stdout to /dev/null */
+ if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
+ (void) CLOSE (nullfd);
+ return GNUNET_SYSERR;
+ }
+ (void) CLOSE (nullfd);
+ /* Detach from controlling terminal */
+ pid = setsid ();
+ if (-1 == pid)
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
+ sctx->ready_confirm_fd = filedes[1];
+#else
+ /* FIXME: we probably need to do something else
+ * elsewhere in order to fork the process itself... */
+ FreeConsole ();
+#endif
+ return GNUNET_OK;
+}
+
+
+/**
+ * Set user ID.
+ *
+ * @param sctx service context
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+set_user_id (struct GNUNET_SERVICE_Context *sctx)
+{
+ char *user;
+
+ if (NULL == (user = get_user_name (sctx)))
+ return GNUNET_OK; /* keep */
+#ifndef MINGW
+ struct passwd *pws;
+
+ errno = 0;
+ pws = getpwnam (user);
+ if (NULL == pws)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Cannot obtain information about user `%s': %s\n"), user,
+ errno == 0 ? _("No such user") : STRERROR (errno));
+ GNUNET_free (user);
+ return GNUNET_SYSERR;
+ }
+ if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
+#if HAVE_INITGROUPS
+ (0 != initgroups (user, pws->pw_gid)) ||
+#endif
+ (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
+ {
+ if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
+ (0 != setreuid (pws->pw_uid, pws->pw_uid)))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s':
%s\n"),
+ user, STRERROR (errno));
+ GNUNET_free (user);
+ return GNUNET_SYSERR;
+ }
+ }
+#endif
+ GNUNET_free (user);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Delete the PID file that was created by our parent.
+ *
+ * @param sctx service context
+ */
+static void
+pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
+{
+ char *pif = get_pid_file_name (sctx);
+
+ if (NULL == pif)
+ return; /* no PID file */
+ if (0 != UNLINK (pif))
+ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
+ GNUNET_free (pif);
+}
+
+
+/**
+ * Run a standard GNUnet service startup sequence (initialize loggers
+ * and configuration, parse options).
+ *
+ * @param argc number of command line arguments
+ * @param argv command line arguments
+ * @param service_name our service name
+ * @param options service options
+ * @param task main task of the service
+ * @param task_cls closure for @a task
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK
+ * if we shutdown nicely
+ */
+int
+GNUNET_SERVICE_run (int argc, char *const *argv,
+ const char *service_name,
+ enum GNUNET_SERVICE_Options options,
+ GNUNET_SERVICE_Main task,
+ void *task_cls)
+{
+#define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0)
+
+ int err;
+ int ret;
+ char *cfg_fn;
+ char *opt_cfg_fn;
+ char *loglev;
+ char *logfile;
+ int do_daemonize;
+ unsigned int i;
+ unsigned long long skew_offset;
+ unsigned long long skew_variance;
+ long long clock_offset;
+ struct GNUNET_SERVICE_Context sctx;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ const char *xdg;
+
+ struct GNUNET_GETOPT_CommandLineOption service_options[] = {
+ GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_fn),
+ {'d', "daemonize", NULL,
+ gettext_noop ("do daemonize (detach from terminal)"), 0,
+ GNUNET_GETOPT_set_one, &do_daemonize},
+ GNUNET_GETOPT_OPTION_HELP (NULL),
+ GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
+ GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
+ GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
+ GNUNET_GETOPT_OPTION_END
+ };
+ err = 1;
+ do_daemonize = 0;
+ logfile = NULL;
+ loglev = NULL;
+ opt_cfg_fn = NULL;
+ xdg = getenv ("XDG_CONFIG_HOME");
+ if (NULL != xdg)
+ GNUNET_asprintf (&cfg_fn,
+ "%s%s%s",
+ xdg,
+ DIR_SEPARATOR_STR,
+ GNUNET_OS_project_data_get ()->config_file);
+ else
+ cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
+ memset (&sctx, 0, sizeof (sctx));
+ sctx.options = options;
+ sctx.ready_confirm_fd = -1;
+ sctx.ret = GNUNET_OK;
+ sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+ sctx.task = task;
+ sctx.task_cls = task_cls;
+ sctx.service_name = service_name;
+ sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
+
+ /* setup subsystems */
+ ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
+ if (GNUNET_SYSERR == ret)
+ goto shutdown;
+ if (GNUNET_NO == ret)
+ {
+ err = 0;
+ goto shutdown;
+ }
+ if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
+ HANDLE_ERROR;
+ if (NULL == opt_cfg_fn)
+ opt_cfg_fn = GNUNET_strdup (cfg_fn);
+ if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
+ {
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Malformed configuration file `%s', exit ...\n"),
+ opt_cfg_fn);
+ goto shutdown;
+ }
+ }
+ else
+ {
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Malformed configuration, exit ...\n"));
+ goto shutdown;
+ }
+ if (0 != strcmp (opt_cfg_fn, cfg_fn))
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not access configuration file `%s'\n"),
+ opt_cfg_fn);
+ }
+ if (GNUNET_OK != setup_service (&sctx))
+ goto shutdown;
+ if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
+ HANDLE_ERROR;
+ if (GNUNET_OK != set_user_id (&sctx))
+ goto shutdown;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Service `%s' runs with configuration from `%s'\n",
+ service_name,
+ opt_cfg_fn);
+ if ((GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
+ "SKEW_OFFSET", &skew_offset)) &&
+ (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
+ "SKEW_VARIANCE",
&skew_variance)))
+ {
+ clock_offset = skew_offset - skew_variance;
+ GNUNET_TIME_set_offset (clock_offset);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
+ }
+ /* actually run service */
+ err = 0;
+ GNUNET_SCHEDULER_run (&service_task, &sctx);
+ /* shutdown */
+ if ((1 == do_daemonize) && (NULL != sctx.server))
+ pid_file_delete (&sctx);
+ GNUNET_free_non_null (sctx.my_handlers);
+
+shutdown:
+ if (-1 != sctx.ready_confirm_fd)
+ {
+ if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
+ GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
+ }
+#if HAVE_MALLINFO
+ {
+ char *counter;
+
+ if ( (GNUNET_YES ==
+ GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name,
+ "GAUGER_HEAP")) &&
+ (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name,
+ "GAUGER_HEAP",
+ &counter)) )
+ {
+ struct mallinfo mi;
+
+ mi = mallinfo ();
+ GAUGER (service_name, counter, mi.usmblks, "blocks");
+ GNUNET_free (counter);
+ }
+ }
+#endif
+ GNUNET_SPEEDUP_stop_ ();
+ GNUNET_CONFIGURATION_destroy (cfg);
+ i = 0;
+ if (NULL != sctx.addrs)
+ while (NULL != sctx.addrs[i])
+ GNUNET_free (sctx.addrs[i++]);
+ GNUNET_free_non_null (sctx.addrs);
+ GNUNET_free_non_null (sctx.addrlens);
+ GNUNET_free_non_null (logfile);
+ GNUNET_free_non_null (loglev);
+ GNUNET_free (cfg_fn);
+ GNUNET_free_non_null (opt_cfg_fn);
+ GNUNET_free_non_null (sctx.v4_denied);
+ GNUNET_free_non_null (sctx.v6_denied);
+ GNUNET_free_non_null (sctx.v4_allowed);
+ GNUNET_free_non_null (sctx.v6_allowed);
+
+ return err ? GNUNET_SYSERR : sctx.ret;
+}
+
+
+/**
+ * Run a service startup sequence within an existing
+ * initialized system.
+ *
+ * @param service_name our service name
+ * @param cfg configuration to use
+ * @param options service options
+ * @return NULL on error, service handle
+ */
+struct GNUNET_SERVICE_Context *
+GNUNET_SERVICE_start (const char *service_name,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ enum GNUNET_SERVICE_Options options)
+{
+ int i;
+ struct GNUNET_SERVICE_Context *sctx;
+
+ sctx = GNUNET_new (struct GNUNET_SERVICE_Context);
+ sctx->ready_confirm_fd = -1; /* no daemonizing */
+ sctx->ret = GNUNET_OK;
+ sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+ sctx->service_name = service_name;
+ sctx->cfg = cfg;
+ sctx->options = options;
+
+ /* setup subsystems */
+ if (GNUNET_OK != setup_service (sctx))
+ {
+ GNUNET_SERVICE_stop (sctx);
+ return NULL;
+ }
+ if (NULL != sctx->lsocks)
+ sctx->server =
+ GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
+ sctx->timeout, sctx->require_found);
+ else
+ sctx->server =
+ GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
+ sctx->timeout, sctx->require_found);
+
+ if (NULL == sctx->server)
+ {
+ GNUNET_SERVICE_stop (sctx);
+ return NULL;
+ }
+#ifndef WINDOWS
+ if (NULL != sctx->addrs)
+ for (i = 0; NULL != sctx->addrs[i]; i++)
+ if ((AF_UNIX == sctx->addrs[i]->sa_family)
+ && ('\0' != ((const struct sockaddr_un
*)sctx->addrs[i])->sun_path[0]))
+ GNUNET_DISK_fix_permissions (((const struct sockaddr_un
*)sctx->addrs[i])->sun_path,
+ sctx->match_uid,
+ sctx->match_gid);
+#endif
+ sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
+ GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
+ i = 0;
+ while ((sctx->my_handlers[i].callback != NULL))
+ sctx->my_handlers[i++].callback_cls = sctx;
+ GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
+ return sctx;
+}
+
+
+/**
+ * Obtain the server used by a service. Note that the server must NOT
+ * be destroyed by the caller.
+ *
+ * @param ctx the service context returned from the start function
+ * @return handle to the server for this service, NULL if there is none
+ */
+struct GNUNET_SERVER_Handle *
+GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx)
+{
+ return ctx->server;
+}
+
+
+/**
+ * Get the NULL-terminated array of listen sockets for this service.
+ *
+ * @param ctx service context to query
+ * @return NULL if there are no listen sockets, otherwise NULL-terminated
+ * array of listen sockets.
+ */
+struct GNUNET_NETWORK_Handle *const*
+GNUNET_SERVICE_get_listen_sockets (struct GNUNET_SERVICE_Context *ctx)
+{
+ return ctx->lsocks;
+}
+
+
+/**
+ * Stop a service that was started with "GNUNET_SERVICE_start".
+ *
+ * @param sctx the service context returned from the start function
+ */
+void
+GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx)
+{
+ unsigned int i;
+
+#if HAVE_MALLINFO
+ {
+ char *counter;
+
+ if ( (GNUNET_YES ==
+ GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
+ "GAUGER_HEAP")) &&
+ (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name,
+ "GAUGER_HEAP",
+ &counter)) )
+ {
+ struct mallinfo mi;
+
+ mi = mallinfo ();
+ GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
+ GNUNET_free (counter);
+ }
+ }
+#endif
+ if (NULL != sctx->shutdown_task)
+ {
+ GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
+ sctx->shutdown_task = NULL;
+ }
+ if (NULL != sctx->server)
+ GNUNET_SERVER_destroy (sctx->server);
+ GNUNET_free_non_null (sctx->my_handlers);
+ if (NULL != sctx->addrs)
+ {
+ i = 0;
+ while (NULL != sctx->addrs[i])
+ GNUNET_free (sctx->addrs[i++]);
+ GNUNET_free (sctx->addrs);
+ }
+ GNUNET_free_non_null (sctx->addrlens);
+ GNUNET_free_non_null (sctx->v4_denied);
+ GNUNET_free_non_null (sctx->v6_denied);
+ GNUNET_free_non_null (sctx->v4_allowed);
+ GNUNET_free_non_null (sctx->v6_allowed);
+ GNUNET_free (sctx);
+}
+
+
+/* end of service.c */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r38186 - in gnunet/src: include util,
gnunet <=