/* This file is part of GNUnet. Copyright (C) 2009-2013, 2016, 2017 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . SPDX-License-Identifier: AGPL3.0-or-later */ /** * @author Christian Grothoff * * @file * Functions related to starting services * * @defgroup service Service library * Start service processes. * * @see [Documentation](https://gnunet.org/developer-handbook-util-services) * * @{ */ #ifndef GNUNET_SERVICE_LIB_H #define GNUNET_SERVICE_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_configuration_lib.h" #include "gnunet_mq_lib.h" /** * Options for the service (bitmask). */ enum GNUNET_SERVICE_Options { /** * Use defaults. Terminates all client connections and the listen * sockets immediately upon receiving the shutdown signal. */ GNUNET_SERVICE_OPTION_NONE = 0, /** * Do not trigger server shutdown on signal at all; instead, allow * for the user to terminate the server explicitly when needed * by calling #GNUNET_SERVICE_shutdown(). */ GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN = 1, /** * Trigger a SOFT server shutdown on signals, allowing active * non-monitor clients to complete their transactions. */ GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN = 2, /** * Bitmask over the shutdown options. */ GNUNET_SERVICE_OPTION_SHUTDOWN_BITMASK = 3, /** * Instead of listening on lsocks passed by the parent, * close them *after* opening our own listen socket(s). */ GNUNET_SERVICE_OPTION_CLOSE_LSOCKS = 4 }; /* **************** NEW SERVICE API ********************** */ /** * Handle to a service. */ struct GNUNET_SERVICE_Handle; /** * Handle to a client that is connected to a service. */ struct GNUNET_SERVICE_Client; /** * Callback to initialize a service, called exactly once when the service is run. * * @param cls closure passed to #GNUNET_SERVICE_MAIN * @param cfg configuration to use for this service * @param sh handle to the newly create service */ typedef void (*GNUNET_SERVICE_InitCallback)(void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_SERVICE_Handle *sh); /** * Callback to be called when a client connects to the service. * * @param cls closure for the service * @param c the new client that connected to the service * @param mq the message queue used to send messages to the client * @return the client-specific (`internal') closure */ typedef void * (*GNUNET_SERVICE_ConnectHandler)(void *cls, struct GNUNET_SERVICE_Client *c, struct GNUNET_MQ_Handle *mq); /** * Callback to be called when a client disconnected from the service * * @param cls closure for the service * @param c the client that disconnected * @param internal_cls the client-specific (`internal') closure */ typedef void (*GNUNET_SERVICE_DisconnectHandler)(void *cls, struct GNUNET_SERVICE_Client *c, void *internal_cls); /** * Low-level function to start a service if the scheduler * is already running. Should only be used directly in * special cases. * * The function will launch the service with the name @a service_name * using the @a service_options to configure its shutdown * behavior. When clients connect or disconnect, the respective * @a connect_cb or @a disconnect_cb functions will be called. For * messages received from the clients, the respective @a handlers will * be invoked; for the closure of the handlers we use the return value * from the @a connect_cb invocation of the respective client. * * Each handler MUST call #GNUNET_SERVICE_client_continue() after each * message to receive further messages from this client. If * #GNUNET_SERVICE_client_continue() is not called within a short * time, a warning will be logged. If delays are expected, services * should call #GNUNET_SERVICE_client_disable_continue_warning() to * disable the warning. * * Clients sending invalid messages (based on @a handlers) will be * dropped. Additionally, clients can be dropped at any time using * #GNUNET_SERVICE_client_drop(). * * The service must be stopped using #GNUNET_SERVICE_stop(). * * @param service_name name of the service to run * @param cfg configuration to use * @param connect_cb function to call whenever a client connects * @param disconnect_cb function to call whenever a client disconnects * @param cls closure argument for @a connect_cb and @a disconnect_cb * @param handlers NULL-terminated array of message handlers for the service, * the closure will be set to the value returned by * the @a connect_cb for the respective connection * @return NULL on error */ struct GNUNET_SERVICE_Handle * GNUNET_SERVICE_start (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_SERVICE_ConnectHandler connect_cb, GNUNET_SERVICE_DisconnectHandler disconnect_cb, void *cls, const struct GNUNET_MQ_MessageHandler *handlers); /** * Stops a service that was started with #GNUNET_SERVICE_start(). * * @param srv service to stop */ void GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv); /** * Creates the "main" function for a GNUnet service. You * should almost always use the #GNUNET_SERVICE_MAIN macro * instead of calling this function directly (except * for ARM, which should call this function directly). * * The function will launch the service with the name @a service_name * using the @a service_options to configure its shutdown * behavior. Once the service is ready, the @a init_cb will be called * for service-specific initialization. @a init_cb will be given the * service handler which can be used to control the service's * availability. When clients connect or disconnect, the respective * @a connect_cb or @a disconnect_cb functions will be called. For * messages received from the clients, the respective @a handlers will * be invoked; for the closure of the handlers we use the return value * from the @a connect_cb invocation of the respective client. * * Each handler MUST call #GNUNET_SERVICE_client_continue() after each * message to receive further messages from this client. If * #GNUNET_SERVICE_client_continue() is not called within a short * time, a warning will be logged. If delays are expected, services * should call #GNUNET_SERVICE_client_disable_continue_warning() to * disable the warning. * * Clients sending invalid messages (based on @a handlers) will be * dropped. Additionally, clients can be dropped at any time using * #GNUNET_SERVICE_client_drop(). * * @param argc number of command-line arguments in @a argv * @param argv array of command-line arguments * @param service_name name of the service to run * @param options options controlling shutdown of the service * @param service_init_cb function to call once the service is ready * @param connect_cb function to call whenever a client connects * @param disconnect_cb function to call whenever a client disconnects * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb * @param handlers NULL-terminated array of message handlers for the service, * the closure will be set to the value returned by * the @a connect_cb for the respective connection * @return 0 on success, non-zero on error */ int GNUNET_SERVICE_run_ (int argc, char *const *argv, const char *service_name, enum GNUNET_SERVICE_Options options, GNUNET_SERVICE_InitCallback service_init_cb, GNUNET_SERVICE_ConnectHandler connect_cb, GNUNET_SERVICE_DisconnectHandler disconnect_cb, void *cls, const struct GNUNET_MQ_MessageHandler *handlers); /** * Creates the "main" function for a GNUnet service. You * MUST use this macro to define GNUnet services (except * for ARM, which MUST NOT use the macro). The reason is * the GNUnet-as-a-library project, where we will not define * a main function anywhere but in ARM. * * The macro will launch the service with the name @a service_name * using the @a service_options to configure its shutdown * behavior. Once the service is ready, the @a init_cb will be called * for service-specific initialization. @a init_cb will be given the * service handler which can be used to control the service's * availability. When clients connect or disconnect, the respective * @a connect_cb or @a disconnect_cb functions will be called. For * messages received from the clients, the respective @a handlers will * be invoked; for the closure of the handlers we use the return value * from the @a connect_cb invocation of the respective client. * * Each handler MUST call #GNUNET_SERVICE_client_continue() after each * message to receive further messages from this client. If * #GNUNET_SERVICE_client_continue() is not called within a short * time, a warning will be logged. If delays are expected, services * should call #GNUNET_SERVICE_client_disable_continue_warning() to * disable the warning. * * Clients sending invalid messages (based on @a handlers) will be * dropped. Additionally, clients can be dropped at any time using * #GNUNET_SERVICE_client_drop(). * * @param service_name name of the service to run * @param options options controlling shutdown of the service * @param service_init_cb function to call once the service is ready * @param connect_cb function to call whenever a client connects * @param disconnect_cb function to call whenever a client disconnects * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb * @param ... array of message handlers for the service, terminated * by #GNUNET_MQ_handler_end(); * the closure will be set to the value returned by * the @a connect_cb for the respective connection * @return 0 on success, non-zero on error * * Sample invocation: * * GNUNET_SERVICE_MAIN * ("resolver", * GNUNET_SERVICE_OPTION_NONE, * &init_cb, * &connect_cb, * &disconnect_cb, * closure_for_cb, * GNUNET_MQ_hd_var_size (get, * GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST, * struct GNUNET_RESOLVER_GetMessage, * NULL), * GNUNET_MQ_handler_end ()); * */ #define GNUNET_SERVICE_MAIN(service_name, service_options, init_cb, connect_cb, \ disconnect_cb, cls, ...) \ int \ main (int argc, \ char *const *argv) \ { \ struct GNUNET_MQ_MessageHandler mh[] = { \ __VA_ARGS__ \ }; \ return GNUNET_SERVICE_run_ (argc, \ argv, \ service_name, \ service_options, \ init_cb, \ connect_cb, \ disconnect_cb, \ cls, \ mh); \ } /** * Suspend accepting connections from the listen socket temporarily. * Resume activity using #GNUNET_SERVICE_resume. * * @param sh service to stop accepting connections. */ void GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh); /** * Resume accepting connections from the listen socket. * * @param sh service to resume accepting connections. */ void GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh); /** * Continue receiving further messages from the given client. * Must be called after each message received. * * @param c the client to continue receiving from */ void GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c); /** * Obtain the message queue of @a c. Convenience function. * * @param c the client to continue receiving from * @return the message queue of @a c */ struct GNUNET_MQ_Handle * GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c); /** * Disable the warning the server issues if a message is not * acknowledged in a timely fashion. Use this call if a client is * intentionally delayed for a while. Only applies to the current * message. * * @param c client for which to disable the warning */ void GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c); /** * Ask the server to disconnect from the given client. This is the * same as returning #GNUNET_SYSERR within the check procedure when * handling a message, except that it allows dropping of a client even * when not handling a message from that client. The `disconnect_cb` * will be called on @a c even if the application closes the connection * using this function. * * This function should be called (outside of util's internal logic) * if (and usually only if) the client has violated the * protocol. Otherwise, we should leave it to the client to disconnect * from the service. * * @param c client to disconnect now */ void GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c); /** * Explicitly stops the service. * * @param sh server to shutdown */ void GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh); /** * Set the 'monitor' flag on this client. Clients which have been * marked as 'monitors' won't prevent the server from shutting down * once #GNUNET_SERVICE_stop_listening() has been invoked. The idea is * that for "normal" clients we likely want to allow them to process * their requests; however, monitor-clients are likely to 'never' * disconnect during shutdown and thus will not be considered when * determining if the server should continue to exist after * shutdown has been triggered. * * @param c client to mark as a monitor */ void GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c); /** * Set the persist option on this client. Indicates that the * underlying socket or fd should never really be closed. Used for * indicating process death. * * @param c client to persist the socket (never to be closed) */ void GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_SERVICE_LIB_H */ #endif /** @} */ /* end of group service */ /* end of gnunet_service_lib.h */