diff options
Diffstat (limited to 'src/util/service.c')
-rw-r--r-- | src/util/service.c | 142 |
1 files changed, 99 insertions, 43 deletions
diff --git a/src/util/service.c b/src/util/service.c index 2c280f5a1..194251af2 100644 --- a/src/util/service.c +++ b/src/util/service.c | |||
@@ -41,10 +41,10 @@ | |||
41 | #define LOG(kind, ...) GNUNET_log_from (kind, "util-service", __VA_ARGS__) | 41 | #define LOG(kind, ...) GNUNET_log_from (kind, "util-service", __VA_ARGS__) |
42 | 42 | ||
43 | #define LOG_STRERROR(kind, syscall) \ | 43 | #define LOG_STRERROR(kind, syscall) \ |
44 | GNUNET_log_from_strerror (kind, "util-service", syscall) | 44 | GNUNET_log_from_strerror (kind, "util-service", syscall) |
45 | 45 | ||
46 | #define LOG_STRERROR_FILE(kind, syscall, filename) \ | 46 | #define LOG_STRERROR_FILE(kind, syscall, filename) \ |
47 | GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename) | 47 | GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename) |
48 | 48 | ||
49 | 49 | ||
50 | /** | 50 | /** |
@@ -1923,47 +1923,6 @@ GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv) | |||
1923 | } | 1923 | } |
1924 | 1924 | ||
1925 | 1925 | ||
1926 | /** | ||
1927 | * Creates the "main" function for a GNUnet service. You | ||
1928 | * should almost always use the #GNUNET_SERVICE_MAIN macro | ||
1929 | * instead of calling this function directly (except | ||
1930 | * for ARM, which should call this function directly). | ||
1931 | * | ||
1932 | * The function will launch the service with the name @a service_name | ||
1933 | * using the @a service_options to configure its shutdown | ||
1934 | * behavior. Once the service is ready, the @a init_cb will be called | ||
1935 | * for service-specific initialization. @a init_cb will be given the | ||
1936 | * service handler which can be used to control the service's | ||
1937 | * availability. When clients connect or disconnect, the respective | ||
1938 | * @a connect_cb or @a disconnect_cb functions will be called. For | ||
1939 | * messages received from the clients, the respective @a handlers will | ||
1940 | * be invoked; for the closure of the handlers we use the return value | ||
1941 | * from the @a connect_cb invocation of the respective client. | ||
1942 | * | ||
1943 | * Each handler MUST call #GNUNET_SERVICE_client_continue() after each | ||
1944 | * message to receive further messages from this client. If | ||
1945 | * #GNUNET_SERVICE_client_continue() is not called within a short | ||
1946 | * time, a warning will be logged. If delays are expected, services | ||
1947 | * should call #GNUNET_SERVICE_client_disable_continue_warning() to | ||
1948 | * disable the warning. | ||
1949 | * | ||
1950 | * Clients sending invalid messages (based on @a handlers) will be | ||
1951 | * dropped. Additionally, clients can be dropped at any time using | ||
1952 | * #GNUNET_SERVICE_client_drop(). | ||
1953 | * | ||
1954 | * @param argc number of command-line arguments in @a argv | ||
1955 | * @param argv array of command-line arguments | ||
1956 | * @param service_name name of the service to run | ||
1957 | * @param options options controlling shutdown of the service | ||
1958 | * @param service_init_cb function to call once the service is ready | ||
1959 | * @param connect_cb function to call whenever a client connects | ||
1960 | * @param disconnect_cb function to call whenever a client disconnects | ||
1961 | * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb | ||
1962 | * @param handlers NULL-terminated array of message handlers for the service, | ||
1963 | * the closure will be set to the value returned by | ||
1964 | * the @a connect_cb for the respective connection | ||
1965 | * @return 0 on success, non-zero on error | ||
1966 | */ | ||
1967 | int | 1926 | int |
1968 | GNUNET_SERVICE_run_ (int argc, | 1927 | GNUNET_SERVICE_run_ (int argc, |
1969 | char *const *argv, | 1928 | char *const *argv, |
@@ -2177,6 +2136,103 @@ shutdown: | |||
2177 | return err ? GNUNET_SYSERR : sh.ret; | 2136 | return err ? GNUNET_SYSERR : sh.ret; |
2178 | } | 2137 | } |
2179 | 2138 | ||
2139 | struct ServiceHandleList | ||
2140 | { | ||
2141 | struct ServiceHandleList *prev; | ||
2142 | struct ServiceHandleList *next; | ||
2143 | |||
2144 | struct GNUNET_SERVICE_Handle *sh; | ||
2145 | }; | ||
2146 | |||
2147 | int | ||
2148 | GNUNET_SERVICE_register_ (const char *service_name, | ||
2149 | enum GNUNET_SERVICE_Options options, | ||
2150 | GNUNET_SERVICE_InitCallback service_init_cb, | ||
2151 | GNUNET_SERVICE_ConnectHandler connect_cb, | ||
2152 | GNUNET_SERVICE_DisconnectHandler disconnect_cb, | ||
2153 | void *cls, | ||
2154 | const struct GNUNET_MQ_MessageHandler *handlers) | ||
2155 | { | ||
2156 | static struct ServiceHandleList *hll_head = NULL; | ||
2157 | static struct ServiceHandleList *hll_tail = NULL; | ||
2158 | struct ServiceHandleList *hle; | ||
2159 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
2160 | struct GNUNET_SERVICE_Handle *sh = GNUNET_new (struct GNUNET_SERVICE_Handle); | ||
2161 | const char *xdg; | ||
2162 | char *cfg_filename; | ||
2163 | const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get (); | ||
2164 | int err; | ||
2165 | |||
2166 | err = 1; | ||
2167 | xdg = getenv ("XDG_CONFIG_HOME"); | ||
2168 | if (NULL != xdg) | ||
2169 | GNUNET_asprintf (&cfg_filename, | ||
2170 | "%s%s%s", | ||
2171 | xdg, | ||
2172 | DIR_SEPARATOR_STR, | ||
2173 | pd->config_file); | ||
2174 | else | ||
2175 | cfg_filename = GNUNET_strdup (pd->user_config_file); | ||
2176 | sh->ready_confirm_fd = -1; | ||
2177 | sh->options = options; | ||
2178 | cfg = GNUNET_CONFIGURATION_create (); | ||
2179 | sh->cfg = cfg; | ||
2180 | sh->service_init_cb = service_init_cb; | ||
2181 | sh->connect_cb = connect_cb; | ||
2182 | sh->disconnect_cb = disconnect_cb; | ||
2183 | sh->cb_cls = cls; | ||
2184 | sh->handlers = (NULL == pd->agpl_url) | ||
2185 | ? GNUNET_MQ_copy_handlers (handlers) | ||
2186 | : GNUNET_MQ_copy_handlers2 (handlers, &return_agpl, NULL); | ||
2187 | sh->service_name = service_name; | ||
2188 | sh->ret = 0; | ||
2189 | if (GNUNET_YES == GNUNET_DISK_file_test (cfg_filename)) | ||
2190 | { | ||
2191 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, cfg_filename)) | ||
2192 | { | ||
2193 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2194 | _ ("Malformed configuration file `%s', exit ...\n"), | ||
2195 | cfg_filename); | ||
2196 | goto fail; | ||
2197 | } | ||
2198 | } | ||
2199 | else | ||
2200 | { | ||
2201 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL)) | ||
2202 | { | ||
2203 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2204 | _ ("Malformed configuration, exit ...\n")); | ||
2205 | goto fail; | ||
2206 | } | ||
2207 | } | ||
2208 | if (GNUNET_OK != setup_service (sh)) | ||
2209 | goto fail; | ||
2210 | if (GNUNET_OK != set_user_id (sh)) | ||
2211 | goto fail; | ||
2212 | GNUNET_RESOLVER_connect (sh->cfg); | ||
2213 | |||
2214 | /* actually run service */ | ||
2215 | err = 0; | ||
2216 | hle = GNUNET_new (struct ServiceHandleList); | ||
2217 | hle->sh = sh; | ||
2218 | GNUNET_CONTAINER_DLL_insert (hll_head, hll_tail, hle); | ||
2219 | /* shutdown */ | ||
2220 | fail: | ||
2221 | if (-1 != sh->ready_confirm_fd) | ||
2222 | { | ||
2223 | if (1 != write (sh->ready_confirm_fd, err ? "I" : "S", 1)) | ||
2224 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write"); | ||
2225 | GNUNET_break (0 == close (sh->ready_confirm_fd)); | ||
2226 | } | ||
2227 | teardown_service (sh); | ||
2228 | GNUNET_free (sh->handlers); | ||
2229 | GNUNET_SPEEDUP_stop_ (); | ||
2230 | GNUNET_CONFIGURATION_destroy (cfg); | ||
2231 | GNUNET_free (cfg_filename); | ||
2232 | GNUNET_free (sh); | ||
2233 | return err ? GNUNET_SYSERR : sh->ret; | ||
2234 | } | ||
2235 | |||
2180 | 2236 | ||
2181 | /** | 2237 | /** |
2182 | * Suspend accepting connections from the listen socket temporarily. | 2238 | * Suspend accepting connections from the listen socket temporarily. |