From: Christian Grothoff Date: Mon, 11 Jan 2010 14:38:05 +0000 (+0000) Subject: fixing hostlist bugs X-Git-Tag: initial-import-from-subversion-38251~22983 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=ea4fbad68f87cc04acacced941399e08bd1a7644;p=oweals%2Fgnunet.git fixing hostlist bugs --- diff --git a/src/hostlist/hostlist-client.c b/src/hostlist/hostlist-client.c index 9fcf2ded1..6c0629eb3 100644 --- a/src/hostlist/hostlist-client.c +++ b/src/hostlist/hostlist-client.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -31,6 +31,8 @@ #include "gnunet_transport_service.h" #include +#define DEBUG_HOSTLIST_CLIENT GNUNET_NO + /** * Number of connections that we must have to NOT download * hostlists anymore. @@ -107,6 +109,11 @@ static int bogus_url; */ static unsigned int connection_count; +/** + * At what time MUST the current hostlist request be done? + */ +static struct GNUNET_TIME_Absolute end_time; + /** * Process downloaded bits by calling callback on each HELLO. @@ -163,9 +170,11 @@ download_hostlist_processor (void *ptr, break; if (GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message*)msg) == msize) { +#if DEBUG_HOSTLIST_CLIENT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received valid `%s' message from hostlist server.\n", "HELLO"); +#endif GNUNET_TRANSPORT_offer_hello (transport, msg); } else @@ -303,6 +312,14 @@ clean_up () } +/** + * Ask CURL for the select set and then schedule the + * receiving task with the scheduler. + */ +static void +run_multi (); + + /** * Task that is run when we are ready to receive more data from the hostlist * server. @@ -317,13 +334,18 @@ multi_ready (void *cls, int running; struct CURLMsg *msg; CURLMcode mret; - + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { +#if DEBUG_HOSTLIST_CLIENT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Shutdown requested while trying to download hostlist from `%s'\n", + current_url); +#endif clean_up (); return; } - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) + if (GNUNET_TIME_absolute_get_remaining (end_time).value == 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Timeout trying to download hostlist from `%s'\n"), @@ -331,6 +353,10 @@ multi_ready (void *cls, clean_up (); return; } +#if DEBUG_HOSTLIST_CLIENT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Ready for processing hostlist client request\n"); +#endif do { running = 0; @@ -346,13 +372,18 @@ multi_ready (void *cls, switch (msg->msg) { case CURLMSG_DONE: - if (msg->data.result != CURLE_OK) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Download of hostlist `%s' completed.\n"), + current_url); + if ( (msg->data.result != CURLE_OK) && + (msg->data.result != CURLE_GOT_NOTHING) ) GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), "curl_multi_perform", __FILE__, __LINE__, - curl_easy_strerror (msg->data.result)); - break; + curl_easy_strerror (msg->data.result)); + clean_up (); + return; default: break; } @@ -368,12 +399,8 @@ multi_ready (void *cls, "curl_multi_perform", __FILE__, __LINE__, curl_multi_strerror (mret)); clean_up (); - return; } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Download of hostlist `%s' completed.\n"), - current_url); - clean_up (); + run_multi (); } @@ -391,8 +418,10 @@ run_multi () int max; struct GNUNET_NETWORK_FDSet *grs; struct GNUNET_NETWORK_FDSet *gws; + long timeout; + struct GNUNET_TIME_Relative rtime; - max = 0; + max = -1; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); @@ -406,15 +435,32 @@ run_multi () clean_up (); return; } + mret = curl_multi_timeout (multi, &timeout); + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("%s failed at %s:%d: `%s'\n"), + "curl_multi_timeout", __FILE__, __LINE__, + curl_multi_strerror (mret)); + clean_up (); + return; + } + rtime = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (end_time), + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + timeout)); grs = GNUNET_NETWORK_fdset_create (); gws = GNUNET_NETWORK_fdset_create (); - GNUNET_NETWORK_fdset_copy_native (grs, &rs, max); - GNUNET_NETWORK_fdset_copy_native (gws, &ws, max); + GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); + GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); +#if DEBUG_HOSTLIST_CLIENT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling task for hostlist download using cURL\n"); +#endif current_task = GNUNET_SCHEDULER_add_select (sched, GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_SCHEDULER_NO_TASK, - GNUNET_TIME_UNIT_MINUTES, + rtime, grs, gws, &multi_ready, @@ -442,7 +488,6 @@ download_hostlist () clean_up (); return; } - transport = GNUNET_TRANSPORT_connect (sched, cfg, NULL, NULL, NULL, NULL); current_url = get_url (); GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, _("Bootstrapping using hostlist at `%s'.\n"), @@ -469,6 +514,7 @@ download_hostlist () return; } CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1); + CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4); /* no need to abort if the above failed */ CURL_EASY_SETOPT (curl, CURLOPT_URL, @@ -481,6 +527,11 @@ download_hostlist () CURL_EASY_SETOPT (curl, CURLOPT_FAILONERROR, 1); +#if 0 + CURL_EASY_SETOPT (curl, + CURLOPT_VERBOSE, + 1); +#endif CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE); @@ -488,10 +539,16 @@ download_hostlist () CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet"); CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, - 150L); + 60L); + CURL_EASY_SETOPT (curl, + CURLOPT_TIMEOUT, + 60L); +#if 0 + /* this should no longer be needed; we're now single-threaded! */ CURL_EASY_SETOPT (curl, CURLOPT_NOSIGNAL, 1); +#endif multi = curl_multi_init (); if (multi == NULL) { @@ -516,7 +573,8 @@ download_hostlist () clean_up (); return; } - run_multi (multi); + end_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); + run_multi (); } @@ -558,13 +616,16 @@ schedule_hostlist_task () hostlist_delay = GNUNET_TIME_UNIT_SECONDS; else hostlist_delay = GNUNET_TIME_relative_multiply (hostlist_delay, 2); - if (hostlist_delay.value > GNUNET_TIME_UNIT_HOURS.value * connection_count) - hostlist_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, - connection_count); + if (hostlist_delay.value > GNUNET_TIME_UNIT_HOURS.value * (1 + connection_count)) + hostlist_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, + (1 + connection_count)); GNUNET_STATISTICS_set (stats, gettext_noop("Minimum time between hostlist downloads"), hostlist_delay.value, GNUNET_YES); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Will consider downloading hostlist in %llums\n"), + (unsigned long long) delay.value); current_task = GNUNET_SCHEDULER_add_delayed (sched, delay, &check_task, @@ -615,8 +676,10 @@ primary_task (void *cls, int success) { if (stats == NULL) return; /* in shutdown */ +#if DEBUG_HOSTLIST_CLIENT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Statistics request done, scheduling hostlist download\n"); +#endif schedule_hostlist_task (); } @@ -651,6 +714,12 @@ GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c, GNUNET_break (0); return GNUNET_SYSERR; } + transport = GNUNET_TRANSPORT_connect (s, c, NULL, NULL, NULL, NULL); + if (NULL == transport) + { + curl_global_cleanup (); + return GNUNET_SYSERR; + } cfg = c; sched = s; stats = st; @@ -679,19 +748,21 @@ GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c, void GNUNET_HOSTLIST_client_stop () { +#if DEBUG_HOSTLIST_CLIENT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist client shutdown\n"); +#endif if (current_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (sched, current_task); - if (transport != NULL) - { - GNUNET_TRANSPORT_disconnect (transport); - transport = NULL; - } curl_global_cleanup (); } + if (transport != NULL) + { + GNUNET_TRANSPORT_disconnect (transport); + transport = NULL; + } GNUNET_assert (NULL == transport); GNUNET_free_non_null (proxy); proxy = NULL; diff --git a/src/hostlist/hostlist-server.c b/src/hostlist/hostlist-server.c index a928040fa..06a17a2ef 100644 --- a/src/hostlist/hostlist-server.c +++ b/src/hostlist/hostlist-server.c @@ -30,15 +30,22 @@ #include "gnunet_hello_lib.h" #include "gnunet_peerinfo_service.h" +#define DEBUG_HOSTLIST_SERVER GNUNET_NO + /** * How often should we recalculate our response to hostlist requests? */ #define RESPONSE_UPDATE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) /** - * Handle to the HTTP server as provided by libmicrohttpd. + * Handle to the HTTP server as provided by libmicrohttpd for IPv6. + */ +static struct MHD_Daemon *daemon_handle_v6; + +/** + * Handle to the HTTP server as provided by libmicrohttpd for IPv4. */ -static struct MHD_Daemon *daemon_handle; +static struct MHD_Daemon *daemon_handle_v4; /** * Our configuration. @@ -51,9 +58,14 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_SCHEDULER_Handle *sched; /** - * Our primary task. + * Our primary task for IPv4. + */ +static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v4; + +/** + * Our primary task for IPv6. */ -static GNUNET_SCHEDULER_TaskIdentifier hostlist_task; +static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v6; /** * Task that updates our HTTP response. @@ -94,9 +106,15 @@ finish_response (struct HostSet *results) if (response != NULL) MHD_destroy_response (response); +#if DEBUG_HOSTLIST_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating hostlist response with %u bytes\n", + (unsigned int) results->size); +#endif response = MHD_create_response_from_data (results->size, results->data, MHD_YES, MHD_NO); - if (daemon_handle != NULL) + if ( (daemon_handle_v4 != NULL) || + (daemon_handle_v6 != NULL) ) { freq = RESPONSE_UPDATE_FREQUENCY; if (results->size == 0) @@ -109,6 +127,7 @@ finish_response (struct HostSet *results) } else { + /* already past shutdown */ MHD_destroy_response (response); response = NULL; } @@ -137,6 +156,13 @@ host_processor (void *cls, } old = results->size; s = GNUNET_HELLO_size(hello); +#if DEBUG_HOSTLIST_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received %u bytes of `%s' from peer `%s' for hostlist.\n", + (unsigned int) s, + "HELLO", + GNUNET_i2s (peer)); +#endif if (old + s >= GNUNET_MAX_MALLOC_CHECKED) return; /* too large, skip! */ GNUNET_array_grow (results->data, @@ -163,9 +189,6 @@ update_response (void *cls, GNUNET_TIME_UNIT_MINUTES, &host_processor, results); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Created new hostlist response with %u bytes\n"), - results->size); } @@ -178,8 +201,10 @@ accept_policy_callback (void *cls, { if (NULL == response) { +#if DEBUG_HOSTLIST_SERVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received request for hostlist, but I am not yet ready; rejecting!\n"); +#endif return MHD_NO; } return MHD_YES; /* accept all */ @@ -201,18 +226,37 @@ access_handler_callback (void *cls, static int dummy; if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) - return MHD_NO; + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Refusing `%s' request to hostlist server\n"), + method); + return MHD_NO; + } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Received request for our hostlist\n")); if (NULL == *con_cls) { (*con_cls) = &dummy; +#if DEBUG_HOSTLIST_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Sending 100 CONTINUE reply\n")); +#endif return MHD_YES; /* send 100 continue */ } if (*upload_data_size != 0) - return MHD_NO; /* do not support upload data */ + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Refusing `%s' request with %llu bytes of upload data\n"), + method, + (unsigned long long) *upload_data_size); + return MHD_NO; /* do not support upload data */ + } if (response == NULL) - return MHD_NO; /* internal error, no response yet */ + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Could not handle hostlist request since I do not have a response yet\n")); + return MHD_NO; /* internal error, no response yet */ + } return MHD_queue_response (connection, MHD_HTTP_OK, response); } @@ -221,9 +265,8 @@ access_handler_callback (void *cls, * Function that queries MHD's select sets and * starts the task waiting for them. */ -static void -prepare_daemon (void); - +static GNUNET_SCHEDULER_TaskIdentifier +prepare_daemon (struct MHD_Daemon *daemon_handle); /** * Call MHD to process pending requests and then go back @@ -233,8 +276,20 @@ static void run_daemon (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { + struct MHD_Daemon *daemon_handle = cls; + + if (daemon_handle == daemon_handle_v4) + hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK; + else + hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; GNUNET_assert (MHD_YES == MHD_run (daemon_handle)); - prepare_daemon (); + if (daemon_handle == daemon_handle_v4) + hostlist_task_v4 = prepare_daemon (daemon_handle); + else + hostlist_task_v6 = prepare_daemon (daemon_handle); } @@ -242,9 +297,10 @@ run_daemon (void *cls, * Function that queries MHD's select sets and * starts the task waiting for them. */ -static void -prepare_daemon () +static GNUNET_SCHEDULER_TaskIdentifier +prepare_daemon (struct MHD_Daemon *daemon_handle) { + GNUNET_SCHEDULER_TaskIdentifier ret; fd_set rs; fd_set ws; fd_set es; @@ -277,18 +333,18 @@ prepare_daemon () GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max); GNUNET_NETWORK_fdset_copy_native (wws, &ws, max); GNUNET_NETWORK_fdset_copy_native (wes, &es, max); - hostlist_task - = GNUNET_SCHEDULER_add_select (sched, - GNUNET_SCHEDULER_PRIORITY_HIGH, - GNUNET_SCHEDULER_NO_TASK, - tv, - wrs, - wws, - &run_daemon, - NULL); + ret = GNUNET_SCHEDULER_add_select (sched, + GNUNET_SCHEDULER_PRIORITY_HIGH, + GNUNET_SCHEDULER_NO_TASK, + tv, + wrs, + wws, + &run_daemon, + daemon_handle); GNUNET_NETWORK_fdset_destroy (wrs); GNUNET_NETWORK_fdset_destroy (wws); GNUNET_NETWORK_fdset_destroy (wes); + return ret; } @@ -315,25 +371,49 @@ GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c, GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Hostlist service starts on port %llu\n"), port); - daemon_handle = MHD_start_daemon (MHD_USE_IPv6, - (unsigned short) port, - &accept_policy_callback, - NULL, - &access_handler_callback, - NULL, - MHD_OPTION_CONNECTION_LIMIT, 16, - MHD_OPTION_PER_IP_CONNECTION_LIMIT, 1, - MHD_OPTION_CONNECTION_TIMEOUT, 16, - MHD_OPTION_CONNECTION_MEMORY_LIMIT, - 16 * 1024, MHD_OPTION_END); - if (daemon_handle == NULL) + daemon_handle_v6 = MHD_start_daemon (MHD_USE_IPv6 +#if DEBUG_HOSTLIST_SERVER + | MHD_USE_DEBUG +#endif + , + (unsigned short) port, + &accept_policy_callback, + NULL, + &access_handler_callback, + NULL, + MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16, + MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1, + MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024), + MHD_OPTION_END); + daemon_handle_v4 = MHD_start_daemon (MHD_NO_FLAG +#if DEBUG_HOSTLIST_SERVER + | MHD_USE_DEBUG +#endif + , + (unsigned short) port, + &accept_policy_callback, + NULL, + &access_handler_callback, + NULL, + MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16, + MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1, + MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024), + MHD_OPTION_END); + + if ( (daemon_handle_v6 == NULL) && + (daemon_handle_v4 == NULL) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not start hostlist HTTP server on port %u\n"), (unsigned short) port); return GNUNET_SYSERR; } - prepare_daemon (); + if (daemon_handle_v4 != NULL) + hostlist_task_v4 = prepare_daemon (daemon_handle_v4); + if (daemon_handle_v6 != NULL) + hostlist_task_v6 = prepare_daemon (daemon_handle_v6); response_task = GNUNET_SCHEDULER_add_now (sched, &update_response, NULL); @@ -346,22 +426,34 @@ GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c, void GNUNET_HOSTLIST_server_stop () { +#if DEBUG_HOSTLIST_SERVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist server shutdown\n"); - if (GNUNET_SCHEDULER_NO_TASK != hostlist_task) +#endif + if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v6) + { + GNUNET_SCHEDULER_cancel (sched, hostlist_task_v6); + hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v4) { - GNUNET_SCHEDULER_cancel (sched, hostlist_task); - hostlist_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_cancel (sched, hostlist_task_v4); + hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != response_task) { GNUNET_SCHEDULER_cancel (sched, response_task); response_task = GNUNET_SCHEDULER_NO_TASK; } - if (NULL != daemon_handle) + if (NULL != daemon_handle_v4) + { + MHD_stop_daemon (daemon_handle_v4); + daemon_handle_v4 = NULL; + } + if (NULL != daemon_handle_v6) { - MHD_stop_daemon (daemon_handle); - daemon_handle = NULL; + MHD_stop_daemon (daemon_handle_v6); + daemon_handle_v6 = NULL; } if (response != NULL) { diff --git a/src/hostlist/test_gnunet_daemon_hostlist.c b/src/hostlist/test_gnunet_daemon_hostlist.c index 66fbf35aa..d6f0468de 100644 --- a/src/hostlist/test_gnunet_daemon_hostlist.c +++ b/src/hostlist/test_gnunet_daemon_hostlist.c @@ -257,6 +257,8 @@ main (int argc, char *argv[]) int ret; + GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-1"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-2"); GNUNET_log_setup ("test-gnunet-daemon-hostlist", #if VERBOSE "DEBUG", @@ -265,6 +267,8 @@ main (int argc, char *argv[]) #endif NULL); ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-1"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-2"); return ret; } diff --git a/src/hostlist/test_gnunet_daemon_hostlist_peer1.conf b/src/hostlist/test_gnunet_daemon_hostlist_peer1.conf index 6d15d4394..e8db94bc9 100644 --- a/src/hostlist/test_gnunet_daemon_hostlist_peer1.conf +++ b/src/hostlist/test_gnunet_daemon_hostlist_peer1.conf @@ -32,4 +32,4 @@ WEAKRANDOM = YES [hostlist] HTTPPORT = 12980 SERVERS = http://localhost:12981/ -OPTIONS = -b -p -L DEBUG \ No newline at end of file +OPTIONS = -b -p diff --git a/src/hostlist/test_gnunet_daemon_hostlist_peer2.conf b/src/hostlist/test_gnunet_daemon_hostlist_peer2.conf index 3cf1ff202..cb64137e8 100644 --- a/src/hostlist/test_gnunet_daemon_hostlist_peer2.conf +++ b/src/hostlist/test_gnunet_daemon_hostlist_peer2.conf @@ -32,4 +32,4 @@ WEAKRANDOM = YES [hostlist] HTTPPORT = 12981 SERVERS = http://localhost:12980/ -OPTIONS = -b -p -L DEBUG +OPTIONS = -b -p