summaryrefslogtreecommitdiff
path: root/src/testbed-logger
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-06-24 14:05:58 +0000
committerChristian Grothoff <christian@grothoff.org>2016-06-24 14:05:58 +0000
commit71c68d0bbdb546bfe84b4536b447899c53cb3812 (patch)
treecbde440932f0b8c038a6559f880a9ecb0de719d9 /src/testbed-logger
parent7093450cf4d9e0654a128aaff442fc6f6809326e (diff)
downloadgnunet-71c68d0bbdb546bfe84b4536b447899c53cb3812.tar.gz
gnunet-71c68d0bbdb546bfe84b4536b447899c53cb3812.zip
move testbed logger to its own directory
Diffstat (limited to 'src/testbed-logger')
-rw-r--r--src/testbed-logger/Makefile.am57
-rw-r--r--src/testbed-logger/gnunet-service-testbed-logger.c270
-rw-r--r--src/testbed-logger/test_testbed_logger_api.c272
-rw-r--r--src/testbed-logger/test_testbed_logger_api.conf6
-rw-r--r--src/testbed-logger/testbed-logger.conf.in127
-rw-r--r--src/testbed-logger/testbed_logger_api.c490
6 files changed, 1222 insertions, 0 deletions
diff --git a/src/testbed-logger/Makefile.am b/src/testbed-logger/Makefile.am
new file mode 100644
index 000000000..7f372fd02
--- /dev/null
+++ b/src/testbed-logger/Makefile.am
@@ -0,0 +1,57 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if MINGW
5 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
6endif
7
8if USE_COVERAGE
9 AM_CFLAGS = --coverage -O0
10 XLIB = -lgcov
11endif
12
13libexecdir= $(pkglibdir)/libexec/
14
15pkgcfgdir= $(pkgdatadir)/config.d/
16
17pkgcfg_DATA = \
18 testbed-logger.conf
19
20libexec_PROGRAMS = \
21 gnunet-service-testbed-logger
22
23gnunet_service_testbed_logger_SOURCES = \
24 gnunet-service-testbed-logger.c
25gnunet_service_testbed_logger_LDADD = \
26 $(top_builddir)/src/util/libgnunetutil.la
27
28lib_LTLIBRARIES = \
29 libgnunettestbedlogger.la
30
31libgnunettestbedlogger_la_SOURCES = \
32 testbed_logger_api.c
33libgnunettestbedlogger_la_LIBADD = $(XLIB) \
34 $(top_builddir)/src/util/libgnunetutil.la \
35 $(LTLIBINTL)
36libgnunettestbedlogger_la_LDFLAGS = \
37 $(GN_LIB_LDFLAGS) \
38 -version-info 0:0:0
39
40check_PROGRAMS = \
41 test_testbed_logger_api
42
43if ENABLE_TEST_RUN
44 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;
45 TESTS = \
46 test_testbed_logger_api
47endif
48
49test_testbed_logger_api_SOURCES = \
50 test_testbed_logger_api.c
51test_testbed_logger_api_LDADD = \
52 $(top_builddir)/src/util/libgnunetutil.la \
53 $(top_builddir)/src/testing/libgnunettesting.la \
54 libgnunettestbedlogger.la
55
56EXTRA_DIST = \
57 test_testbed_logger_api.conf
diff --git a/src/testbed-logger/gnunet-service-testbed-logger.c b/src/testbed-logger/gnunet-service-testbed-logger.c
new file mode 100644
index 000000000..1c250b306
--- /dev/null
+++ b/src/testbed-logger/gnunet-service-testbed-logger.c
@@ -0,0 +1,270 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file testbed-logger/gnunet-service-testbed-logger.c
23 * @brief service for collecting messages and writing to a file
24 * @author Sree Harsha Totakura
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30/**
31 * Generic logging shorthand
32 */
33#define LOG(type, ...) \
34 GNUNET_log (type, __VA_ARGS__)
35
36/**
37 * Debug logging shorthand
38 */
39#define LOG_DEBUG(...) \
40 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
41
42/**
43 * The message queue for sending messages to clients
44 */
45struct MessageQueue
46{
47 /**
48 * The message to be sent
49 */
50 struct GNUNET_MessageHeader *msg;
51
52 /**
53 * The client to send the message to
54 */
55 struct GNUNET_SERVER_Client *client;
56
57 /**
58 * next pointer for DLL
59 */
60 struct MessageQueue *next;
61
62 /**
63 * prev pointer for DLL
64 */
65 struct MessageQueue *prev;
66};
67
68/**
69 * The message queue head
70 */
71static struct MessageQueue *mq_head;
72
73/**
74 * The message queue tail
75 */
76static struct MessageQueue *mq_tail;
77
78/**
79 * Handle for buffered writing.
80 */
81struct GNUNET_BIO_WriteHandle *bio;
82
83/**
84 * The number of connections we have
85 */
86static unsigned int nconn;
87
88/**
89 * Are we shutting down?
90 */
91static int in_shutdown;
92
93
94/**
95 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
96 *
97 * @param cls NULL
98 * @param client identification of the client
99 * @param msg the actual message
100 */
101static void
102handle_log_msg (void *cls,
103 struct GNUNET_SERVER_Client *client,
104 const struct GNUNET_MessageHeader *msg)
105{
106 uint16_t ms;
107
108 ms = ntohs (msg->size);
109 ms -= sizeof (struct GNUNET_MessageHeader);
110 GNUNET_BIO_write (bio, &msg[1], ms);
111 GNUNET_SERVER_receive_done (client, GNUNET_OK);
112}
113
114
115/**
116 * Task to clean up and shutdown nicely
117 *
118 * @param cls NULL
119 */
120static void
121shutdown_task (void *cls)
122{
123 struct MessageQueue *mq_entry;
124
125 in_shutdown = GNUNET_YES;
126 if (0 != nconn)
127 {
128 /* Delay shutdown if there are active connections */
129 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
130 return;
131 }
132 while (NULL != (mq_entry = mq_head))
133 {
134 GNUNET_free (mq_entry->msg);
135 GNUNET_SERVER_client_drop (mq_entry->client);
136 GNUNET_CONTAINER_DLL_remove (mq_head,
137 mq_tail,
138 mq_entry);
139 GNUNET_free (mq_entry);
140 }
141 GNUNET_break (GNUNET_OK == GNUNET_BIO_write_close (bio));
142}
143
144
145/**
146x * Functions with this signature are called whenever a client
147 * is disconnected on the network level.
148 *
149 * @param cls closure
150 * @param client identification of the client; NULL
151 * for the last call when the server is destroyed
152 */
153static void
154client_disconnected (void *cls,
155 struct GNUNET_SERVER_Client *client)
156{
157 if (NULL == client)
158 {
159 GNUNET_break (0 == nconn);
160 return;
161 }
162 nconn--;
163 if (GNUNET_YES == in_shutdown)
164 GNUNET_SCHEDULER_shutdown ();
165}
166
167
168/**
169 * Functions with this signature are called whenever a client
170 * is connected on the network level.
171 *
172 * @param cls closure
173 * @param client identification of the client
174 */
175static void
176client_connected (void *cls,
177 struct GNUNET_SERVER_Client *client)
178{
179 if (NULL == client)
180 {
181 GNUNET_break (0 == nconn);
182 return;
183 }
184 GNUNET_SERVER_client_persist_ (client);
185 nconn++;
186}
187
188
189/**
190 * Testbed setup
191 *
192 * @param cls closure
193 * @param server the initialized server
194 * @param cfg configuration to use
195 */
196static void
197logger_run (void *cls,
198 struct GNUNET_SERVER_Handle *server,
199 const struct GNUNET_CONFIGURATION_Handle *cfg)
200{
201 static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
202 {&handle_log_msg, NULL, GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG, 0},
203 {NULL, NULL, 0, 0}
204 };
205 char *dir;
206 char *fn;
207 char *hname;
208 size_t hname_len;
209 pid_t pid;
210
211 if (GNUNET_OK !=
212 GNUNET_CONFIGURATION_get_value_filename (cfg,
213 "TESTBED-LOGGER",
214 "DIR",
215 &dir))
216 {
217 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
218 "TESTBED-LOGGER",
219 "DIR");
220 GNUNET_SCHEDULER_shutdown ();
221 return;
222 }
223 pid = getpid ();
224 hname_len = GNUNET_OS_get_hostname_max_length ();
225 hname = GNUNET_malloc (hname_len);
226 if (0 != gethostname (hname, hname_len))
227 {
228 LOG (GNUNET_ERROR_TYPE_ERROR,
229 "Cannot get hostname. Exiting\n");
230 GNUNET_free (hname);
231 GNUNET_free (dir);
232 GNUNET_SCHEDULER_shutdown ();
233 return;
234 }
235 GNUNET_asprintf (&fn,
236 "%s/%.*s_%jd.dat",
237 dir,
238 hname_len,
239 hname,
240 (intmax_t) pid);
241 GNUNET_free (hname);
242 GNUNET_free (dir);
243 if (NULL == (bio = GNUNET_BIO_write_open (fn)))
244 {
245 GNUNET_free (fn);
246 GNUNET_SCHEDULER_shutdown ();
247 return;
248 }
249 GNUNET_free (fn);
250 GNUNET_SERVER_add_handlers (server, message_handlers);
251 GNUNET_SERVER_connect_notify (server, &client_connected, NULL);
252 GNUNET_SERVER_disconnect_notify (server, &client_disconnected, NULL);
253 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
254 LOG_DEBUG ("TESTBED-LOGGER startup complete\n");
255}
256
257
258/**
259 * The starting point of execution
260 */
261int
262main (int argc, char *const *argv)
263{
264 return (GNUNET_OK ==
265 GNUNET_SERVICE_run (argc, argv, "testbed-logger",
266 GNUNET_SERVICE_OPTION_NONE,
267 &logger_run, NULL)) ? 0 : 1;
268}
269
270/* end of gnunet-service-testbed-logger.c */
diff --git a/src/testbed-logger/test_testbed_logger_api.c b/src/testbed-logger/test_testbed_logger_api.c
new file mode 100644
index 000000000..8f7391f22
--- /dev/null
+++ b/src/testbed-logger/test_testbed_logger_api.c
@@ -0,0 +1,272 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20/**
21 * @file testbed-logger/test_testbed_logger_api.c
22 * @brief testcases for the testbed logger api
23 * @author Sree Harsha Totakura
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_testing_lib.h"
28#include "gnunet_testbed_logger_service.h"
29
30/**
31 * Generic logging shortcut
32 */
33#define LOG(kind,...) \
34 GNUNET_log (kind, __VA_ARGS__)
35
36/**
37 * Relative time seconds shorthand
38 */
39#define TIME_REL_SECS(sec) \
40 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
41
42/**
43 * Opaque handle for the logging service
44 */
45static struct GNUNET_TESTBED_LOGGER_Handle *h;
46
47static struct GNUNET_TESTING_Peer *peer;
48
49static char *search_dir;
50
51/**
52 * Abort task identifier
53 */
54static struct GNUNET_SCHEDULER_Task *abort_task;
55static struct GNUNET_SCHEDULER_Task *write_task;
56
57static int result;
58
59#define CANCEL_TASK(task) do { \
60 if (NULL != task) \
61 { \
62 GNUNET_SCHEDULER_cancel (task); \
63 task = NULL; \
64 } \
65 } while (0)
66
67/**
68 * shortcut to exit during failure
69 */
70#define FAIL_TEST(cond, ret) do { \
71 if (!(cond)) { \
72 GNUNET_break(0); \
73 CANCEL_TASK (abort_task); \
74 abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL); \
75 ret; \
76 } \
77 } while (0)
78
79
80/**
81 * Shutdown nicely
82 *
83 * @param cls NULL
84 * @param tc the task context
85 */
86static void
87shutdown_now ()
88{
89 CANCEL_TASK (abort_task);
90 CANCEL_TASK (write_task);
91 GNUNET_free_non_null (search_dir);
92 if (NULL != h)
93 GNUNET_TESTBED_LOGGER_disconnect (h);
94 GNUNET_SCHEDULER_shutdown ();
95}
96
97
98static void
99do_abort (void *cls)
100{
101 LOG (GNUNET_ERROR_TYPE_WARNING,
102 "Aborting\n");
103 abort_task = NULL;
104 shutdown_now ();
105}
106
107
108#define BSIZE 1024
109
110
111/**
112 * Function called to iterate over a directory.
113 *
114 * @param cls closure
115 * @param filename complete filename (absolute path)
116 * @return #GNUNET_OK to continue to iterate,
117 * #GNUNET_NO to stop iteration with no error,
118 * #GNUNET_SYSERR to abort iteration with error!
119 */
120static int
121iterator_cb (void *cls,
122 const char *filename)
123{
124 const char *fn;
125 size_t len;
126 uint64_t fs;
127
128 LOG (GNUNET_ERROR_TYPE_DEBUG,
129 "Iterator sees file %s\n",
130 filename);
131 len = strlen (filename);
132 fn = filename + len;
133 if (0 != strcasecmp (".dat", fn - 4))
134 return GNUNET_OK;
135 if (GNUNET_OK !=
136 GNUNET_DISK_file_size (filename,
137 &fs,
138 GNUNET_NO,
139 GNUNET_YES))
140 {
141 LOG (GNUNET_ERROR_TYPE_DEBUG,
142 "Failed to obtain file size for file %s\n",
143 filename);
144 return GNUNET_SYSERR;
145 }
146 if ((BSIZE * 2) != fs)
147 {
148 LOG (GNUNET_ERROR_TYPE_DEBUG,
149 "Unexpected file size for file %s\n",
150 filename);
151 /* The file size should be equal to what we
152 have written */
153 return GNUNET_SYSERR;
154 }
155 result = GNUNET_OK;
156 return GNUNET_OK;
157}
158
159
160/**
161 * Functions of this type are called to notify a successful
162 * transmission of the message to the logger service
163 *
164 * @param cls the closure given to GNUNET_TESTBED_LOGGER_send()
165 * @param size the amount of data sent
166 */
167static void
168flush_comp (void *cls,
169 size_t size)
170{
171 LOG (GNUNET_ERROR_TYPE_DEBUG,
172 "Flush running\n");
173 FAIL_TEST (&write_task == cls,
174 return);
175 FAIL_TEST ((BSIZE * 2) == size,
176 return);
177 FAIL_TEST (GNUNET_OK ==
178 GNUNET_TESTING_peer_stop (peer),
179 return);
180 LOG (GNUNET_ERROR_TYPE_DEBUG,
181 "Peer stopped, scanning %s\n",
182 search_dir);
183 FAIL_TEST (GNUNET_SYSERR !=
184 GNUNET_DISK_directory_scan (search_dir,
185 &iterator_cb,
186 NULL),
187 return);
188 shutdown_now ();
189}
190
191
192static void
193do_write (void *cls)
194{
195 static int i;
196 char buf[BSIZE];
197
198 write_task = NULL;
199 LOG (GNUNET_ERROR_TYPE_DEBUG,
200 "Write task running\n");
201 if (0 == i)
202 write_task = GNUNET_SCHEDULER_add_delayed (TIME_REL_SECS(1),
203 &do_write,
204 NULL);
205 (void) memset (buf, i, BSIZE);
206 GNUNET_TESTBED_LOGGER_write (h,
207 buf,
208 BSIZE);
209 if (0 == i++)
210 return;
211 GNUNET_TESTBED_LOGGER_flush (h,
212 GNUNET_TIME_UNIT_FOREVER_REL,
213 &flush_comp,
214 &write_task);
215}
216
217
218/**
219 * Signature of the 'main' function for a (single-peer) testcase that
220 * is run using #GNUNET_TESTING_peer_run().
221 *
222 * @param cls closure
223 * @param cfg configuration of the peer that was started
224 * @param peer identity of the peer that was created
225 */
226static void
227test_main (void *cls,
228 const struct GNUNET_CONFIGURATION_Handle *cfg,
229 struct GNUNET_TESTING_Peer *p)
230{
231 LOG (GNUNET_ERROR_TYPE_DEBUG,
232 "Connecting to logger\n");
233 FAIL_TEST (NULL != (h = GNUNET_TESTBED_LOGGER_connect (cfg)),
234 return);
235 FAIL_TEST (GNUNET_OK ==
236 GNUNET_CONFIGURATION_get_value_filename (cfg,
237 "testbed-logger",
238 "dir",
239 &search_dir),
240 return);
241 peer = p;
242 write_task = GNUNET_SCHEDULER_add_now (&do_write,
243 NULL);
244 abort_task = GNUNET_SCHEDULER_add_delayed (TIME_REL_SECS (10),
245 &do_abort,
246 NULL);
247}
248
249
250/**
251 * Main function
252 */
253int
254main (int argc, char **argv)
255{
256 int ret;
257
258 result = GNUNET_SYSERR;
259 GNUNET_log_setup ("test-testbed-logger-api",
260 "WARNING",
261 NULL);
262 ret = GNUNET_TESTING_service_run ("test-testbed-logger",
263 "testbed-logger",
264 "test_testbed_logger_api.conf",
265 &test_main,
266 NULL);
267 if (0 != ret)
268 return 1;
269 if (GNUNET_OK != result)
270 return 2;
271 return 0;
272}
diff --git a/src/testbed-logger/test_testbed_logger_api.conf b/src/testbed-logger/test_testbed_logger_api.conf
new file mode 100644
index 000000000..57ce5c254
--- /dev/null
+++ b/src/testbed-logger/test_testbed_logger_api.conf
@@ -0,0 +1,6 @@
1[testbed-logger]
2UNIXPATH=/tmp/testbed-logger.sock
3DIR=$GNUNET_TEST_HOME/data
4
5[PATHS]
6GNUNET_TEST_HOME = /tmp/test-testbed/ \ No newline at end of file
diff --git a/src/testbed-logger/testbed-logger.conf.in b/src/testbed-logger/testbed-logger.conf.in
new file mode 100644
index 000000000..094328c7b
--- /dev/null
+++ b/src/testbed-logger/testbed-logger.conf.in
@@ -0,0 +1,127 @@
1[testbed]
2AUTOSTART = NO
3@JAVAPORT@ PORT = 2101
4HOSTNAME = localhost
5BINARY = gnunet-service-testbed
6
7# How long should operations wait?
8OPERATION_TIMEOUT = 30 s
9
10# Set this to the path where the testbed helper is installed. By default the
11# helper binary is searched in @prefix@/lib/gnunet/libexec/
12# HELPER_BINARY_PATH = @prefix@/lib/gnunet/libexec/gnunet-helper-testbed
13
14# Add your local network address here. For example, if you want to run
15# testbed on a group of hosts connected to network 192.168.1.0/24, then set
16# ACCEPT_FROM = 127.0.0.1; 192.168.1.0/24;
17# Multiple network addresses can be given. They should be separated by `;'
18ACCEPT_FROM = 127.0.0.1;
19ACCEPT_FROM6 = ::1;
20
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-testbed.sock
22UNIX_MATCH_UID = YES
23UNIX_MATCH_GID = YES
24
25# How many maximum number of operations can be run in parallel. This number
26# should be decreased if the system is getting overloaded and to reduce the load
27# exerted by the emulation.
28MAX_PARALLEL_OPERATIONS = 1000
29MAX_PARALLEL_TOPOLOGY_CONFIG_OPERATIONS = 1
30
31# What topology should be generated by the helper functions GNUNET_TESTBED_run()
32# and GNUNET_TESTBED_test_run(). This option has no effect if testbed is
33# initialized with other functions. Valid values can be found at:
34# https://gnunet.org/supported-topologies
35OVERLAY_TOPOLOGY = NONE
36
37# Number of random links to be included to the generate the above topology.
38# Note that not all topologies require this option and ignore it. Topologies
39# requiring this option are RANDOM, SMALL_WORLD and SMALL_WORLD ring.
40# OVERLAY_RANDOM_LINKS =
41
42# This option is required if the OVERLAY_TOPOLOGY is set to FROM_FILE. It is
43# ignored for all other topologies. This option should contain the path to
44# the file containing the topology information. The format of the file is
45# presented at: https://gnunet.org/topology-file-format
46# OVERLAY_TOPOLOGY_FILE = /path/to/topology-file
47
48# The following options are required if the OVERLAY_TOPOLOGY is set to
49# SCALE_FREE. They are ignored in all other cases.
50# The number of maximum peers which can connect to a peer
51SCALE_FREE_TOPOLOGY_CAP = 70
52# The minimum number of peers which a peer has to connect
53SCALE_FREE_TOPOLOGY_M = 5
54
55# How many maximum number of handles to peers' services should be kept open at
56# any time. This number also keeps a check on the number of open descriptors as
57# opening a service connection results in opening a file descriptor.
58MAX_PARALLEL_SERVICE_CONNECTIONS = 256
59
60# Size of the internal testbed cache. It is used to cache handles to peers
61# while trying to connect them.
62CACHE_SIZE = 30
63
64# Maximum number of file descriptors a testbed controller is permitted to keep
65# open.
66MAX_OPEN_FDS = 512
67
68# How long should we wait for testbed to setup while using helper functions
69# GNUNET_TESTBED_test_run() and GNUNET_TESTBED_run()
70SETUP_TIMEOUT = 5 m
71
72# Where should testbed write load statistics data
73# STATS_DIR = /tmp/load
74
75# What services should be shared among peers.
76# Format is "[<service:share>] [<service:share>] ...". The shared services are
77# started standalone without any other peer services or a hostkey. For this
78# reason, only services which doesn't depend on other services can only be
79# shared. Example: To share peerinfo among every 10 peers. The following spec
80# will start 5 peerinfo services when 50 peers are started:
81#
82# SHARED_SERVICES = peerinfo:10
83#
84# To share multiple services
85#
86# SHARED_SERVICES = service1:n_share1 service2:n_share2 ...
87#
88# Default is to share no services
89SHARED_SERVICES =
90
91
92[testbed-logger]
93AUTOSTART = NO
94@UNIXONLY@ PORT = 2102
95HOSTNAME = localhost
96BINARY = gnunet-service-testbed-logger
97UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-gnunet-testbed-logger.sock
98DIR = /tmp
99UNIX_MATCH_UID = YES
100UNIX_MATCH_GID = YES
101
102
103[testbed-barrier]
104AUTOSTART = NO
105@UNIXONLY@ PORT = 2103
106HOSTNAME = localhost
107UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-testbed-barrier.sock
108UNIX_MATCH_UID = YES
109UNIX_MATCH_GID = YES
110
111
112# This section is related to configuring underlay restrictions to simulate
113# connectivity restrictions of NAT boxes
114[testbed-underlay]
115AUTOSTART = NO
116NOARMBIND = YES
117BINARY = gnunet-daemon-testbed-underlay
118# The sqlite3 database file containing information about what underlay
119# restrictions to apply
120# DBFILE =
121
122[latency-logger]
123AUTOSTART = NO
124NOARMBIND = YES
125BINARY = gnunet-daemon-latency-logger
126# The sqlite3 database file where the latency values are to be stored
127# DBFILE = \ No newline at end of file
diff --git a/src/testbed-logger/testbed_logger_api.c b/src/testbed-logger/testbed_logger_api.c
new file mode 100644
index 000000000..aaf18cd33
--- /dev/null
+++ b/src/testbed-logger/testbed_logger_api.c
@@ -0,0 +1,490 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20
21/**
22 * @file testbed-logger/testbed_logger_api.c
23 * @brief Client-side routines for communicating with the tesbted logger service
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_logger_service.h"
30
31/**
32 * Generic logging shorthand
33 */
34#define LOG(kind, ...) \
35 GNUNET_log_from (kind, "testbed-logger-api", __VA_ARGS__)
36
37/**
38 * Debug logging
39 */
40#define LOG_DEBUG(...) \
41 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
42
43#ifdef GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD
44#undef GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD
45#endif
46
47/**
48 * Threshold after which exponential backoff should not increase (15 s).
49 */
50#define GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
51
52/**
53 * The size of the buffer we fill before sending out the message
54 */
55#define BUFFER_SIZE GNUNET_SERVER_MAX_MESSAGE_SIZE
56
57/**
58 * The message queue for sending messages to the controller service
59 */
60struct MessageQueue
61{
62 /**
63 * next pointer for DLL
64 */
65 struct MessageQueue *next;
66
67 /**
68 * prev pointer for DLL
69 */
70 struct MessageQueue *prev;
71
72 /**
73 * The message to be sent
74 */
75 struct GNUNET_MessageHeader *msg;
76
77 /**
78 * Completion callback
79 */
80 GNUNET_TESTBED_LOGGER_FlushCompletion cb;
81
82 /**
83 * callback closure
84 */
85 void *cb_cls;
86};
87
88
89/**
90 * Connection handle for the logger service
91 */
92struct GNUNET_TESTBED_LOGGER_Handle
93{
94 /**
95 * Client connection
96 */
97 struct GNUNET_CLIENT_Connection *client;
98
99 /**
100 * The transport handle
101 */
102 struct GNUNET_CLIENT_TransmitHandle *th;
103
104 /**
105 * DLL head for the message queue
106 */
107 struct MessageQueue *mq_head;
108
109 /**
110 * DLL tail for the message queue
111 */
112 struct MessageQueue *mq_tail;
113
114 /**
115 * Flush completion callback
116 */
117 GNUNET_TESTBED_LOGGER_FlushCompletion cb;
118
119 /**
120 * Closure for the above callback
121 */
122 void *cb_cls;
123
124 /**
125 * Local buffer for data to be transmitted
126 */
127 void *buf;
128
129 /**
130 * The size of the local buffer
131 */
132 size_t bs;
133
134 /**
135 * Number of bytes wrote since last flush
136 */
137 size_t bwrote;
138
139 /**
140 * How long after should we retry sending a message to the service?
141 */
142 struct GNUNET_TIME_Relative retry_backoff;
143
144 /**
145 * Task to call the flush completion callback
146 */
147 struct GNUNET_SCHEDULER_Task * flush_completion_task;
148
149 /**
150 * Task to be executed when flushing takes too long
151 */
152 struct GNUNET_SCHEDULER_Task * timeout_flush_task;
153};
154
155
156/**
157 * Cancels the flush timeout task
158 *
159 * @param h handle to the logger
160 */
161static void
162cancel_timeout_flush (struct GNUNET_TESTBED_LOGGER_Handle *h)
163{
164 GNUNET_SCHEDULER_cancel (h->timeout_flush_task);
165 h->timeout_flush_task = NULL;
166}
167
168
169/**
170 * Task to call the flush completion notification
171 *
172 * @param cls the logger handle
173 */
174static void
175call_flush_completion (void *cls)
176{
177 struct GNUNET_TESTBED_LOGGER_Handle *h = cls;
178 GNUNET_TESTBED_LOGGER_FlushCompletion cb;
179 void *cb_cls;
180 size_t bw;
181
182 h->flush_completion_task = NULL;
183 bw = h->bwrote;
184 h->bwrote = 0;
185 cb = h->cb;
186 h->cb = NULL;
187 cb_cls = h->cb_cls;
188 h->cb_cls = NULL;
189 if (NULL != h->timeout_flush_task)
190 cancel_timeout_flush (h);
191 if (NULL != cb)
192 cb (cb_cls, bw);
193}
194
195
196/**
197 * Schedule the flush completion notification task
198 *
199 * @param h logger handle
200 */
201static void
202trigger_flush_notification (struct GNUNET_TESTBED_LOGGER_Handle *h)
203{
204 if (NULL != h->flush_completion_task)
205 GNUNET_SCHEDULER_cancel (h->flush_completion_task);
206 h->flush_completion_task = GNUNET_SCHEDULER_add_now (&call_flush_completion, h);
207}
208
209
210/**
211 * Function called to notify a client about the connection begin ready to queue
212 * more data. "buf" will be NULL and "size" zero if the connection was closed
213 * for writing in the meantime.
214 *
215 * @param cls closure
216 * @param size number of bytes available in buf
217 * @param buf where the callee should write the message
218 * @return number of bytes written to buf
219 */
220static size_t
221transmit_ready_notify (void *cls, size_t size, void *buf)
222{
223 struct GNUNET_TESTBED_LOGGER_Handle *h = cls;
224 struct MessageQueue *mq;
225
226 h->th = NULL;
227 mq = h->mq_head;
228 GNUNET_assert (NULL != mq);
229 if ((0 == size) && (NULL == buf)) /* Timeout */
230 {
231 LOG_DEBUG ("Message sending timed out -- retrying\n");
232 h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff);
233 h->th =
234 GNUNET_CLIENT_notify_transmit_ready (h->client,
235 ntohs (mq->msg->size),
236 h->retry_backoff, GNUNET_YES,
237 &transmit_ready_notify, h);
238 return 0;
239 }
240 h->retry_backoff = GNUNET_TIME_UNIT_ZERO;
241 GNUNET_assert (ntohs (mq->msg->size) <= size);
242 size = ntohs (mq->msg->size);
243 memcpy (buf, mq->msg, size);
244 LOG_DEBUG ("Message of type: %u and size: %u sent\n",
245 ntohs (mq->msg->type), size);
246 GNUNET_free (mq->msg);
247 GNUNET_CONTAINER_DLL_remove (h->mq_head, h->mq_tail, mq);
248 GNUNET_free (mq);
249 h->bwrote += (size - sizeof (struct GNUNET_MessageHeader));
250 mq = h->mq_head;
251 if (NULL != mq)
252 {
253 h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff);
254 h->th =
255 GNUNET_CLIENT_notify_transmit_ready (h->client,
256 ntohs (mq->msg->size),
257 h->retry_backoff, GNUNET_YES,
258 &transmit_ready_notify, h);
259 return size;
260 }
261 if (NULL != h->cb)
262 trigger_flush_notification (h); /* Call the flush completion callback */
263 return size;
264}
265
266
267/**
268 * Queues a message in send queue of the logger handle
269 *
270 * @param h the logger handle
271 * @param msg the message to queue
272 */
273static void
274queue_message (struct GNUNET_TESTBED_LOGGER_Handle *h,
275 struct GNUNET_MessageHeader *msg)
276{
277 struct MessageQueue *mq;
278 uint16_t type;
279 uint16_t size;
280
281 type = ntohs (msg->type);
282 size = ntohs (msg->size);
283 mq = GNUNET_new (struct MessageQueue);
284 mq->msg = msg;
285 LOG (GNUNET_ERROR_TYPE_DEBUG,
286 "Queueing message of type %u, size %u for sending\n", type,
287 ntohs (msg->size));
288 GNUNET_CONTAINER_DLL_insert_tail (h->mq_head, h->mq_tail, mq);
289 if (NULL == h->th)
290 {
291 h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff);
292 h->th =
293 GNUNET_CLIENT_notify_transmit_ready (h->client, size,
294 h->retry_backoff, GNUNET_YES,
295 &transmit_ready_notify,
296 h);
297 }
298}
299
300
301/**
302 * Send the buffered data to the service
303 *
304 * @param h the logger handle
305 */
306static void
307dispatch_buffer (struct GNUNET_TESTBED_LOGGER_Handle *h)
308{
309 struct GNUNET_MessageHeader *msg;
310 size_t msize;
311
312 msize = sizeof (struct GNUNET_MessageHeader) + h->bs;
313 msg = GNUNET_realloc (h->buf, msize);
314 h->buf = NULL;
315 memmove (&msg[1], msg, h->bs);
316 h->bs = 0;
317 msg->type = htons (GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG);
318 msg->size = htons (msize);
319 queue_message (h, msg);
320}
321
322
323/**
324 * Connect to the testbed logger service
325 *
326 * @param cfg configuration to use
327 * @return the handle which can be used for sending data to the service; NULL
328 * upon any error
329 */
330struct GNUNET_TESTBED_LOGGER_Handle *
331GNUNET_TESTBED_LOGGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
332{
333 struct GNUNET_TESTBED_LOGGER_Handle *h;
334 struct GNUNET_CLIENT_Connection *client;
335
336 client = GNUNET_CLIENT_connect ("testbed-logger", cfg);
337 if (NULL == client)
338 return NULL;
339 h = GNUNET_new (struct GNUNET_TESTBED_LOGGER_Handle);
340 h->client = client;
341 return h;
342}
343
344
345/**
346 * Disconnect from the logger service.
347 *
348 * @param h the logger handle
349 */
350void
351GNUNET_TESTBED_LOGGER_disconnect (struct GNUNET_TESTBED_LOGGER_Handle *h)
352{
353 struct MessageQueue *mq;
354 unsigned int lost;
355
356 if (NULL != h->flush_completion_task)
357 GNUNET_SCHEDULER_cancel (h->flush_completion_task);
358 lost = 0;
359 while (NULL != (mq = h->mq_head))
360 {
361 GNUNET_CONTAINER_DLL_remove (h->mq_head, h->mq_tail, mq);
362 GNUNET_free (mq->msg);
363 GNUNET_free (mq);
364 lost++;
365 }
366 if (0 != lost)
367 LOG (GNUNET_ERROR_TYPE_WARNING, "Cleaning up %u unsent logger message[s]\n",
368 lost);
369 GNUNET_CLIENT_disconnect (h->client);
370 GNUNET_free (h);
371}
372
373
374/**
375 * Send data to be logged to the logger service. The data will be buffered and
376 * will be sent upon an explicit call to GNUNET_TESTBED_LOGGER_flush() or upon
377 * exceeding a threshold size.
378 *
379 * @param h the logger handle
380 * @param data the data to send;
381 * @param size how many bytes of data to send
382 */
383void
384GNUNET_TESTBED_LOGGER_write (struct GNUNET_TESTBED_LOGGER_Handle *h,
385 const void *data, size_t size)
386{
387 size_t fit_size;
388
389 GNUNET_assert (0 != size);
390 GNUNET_assert (NULL != data);
391 GNUNET_assert (size <= (BUFFER_SIZE - sizeof (struct GNUNET_MessageHeader)));
392 fit_size = sizeof (struct GNUNET_MessageHeader) + h->bs + size;
393 if ( BUFFER_SIZE < fit_size )
394 dispatch_buffer (h);
395 if (NULL == h->buf)
396 {
397 h->buf = GNUNET_malloc (size);
398 h->bs = size;
399 memcpy (h->buf, data, size);
400 goto dispatch_ready;
401 }
402 h->buf = GNUNET_realloc (h->buf, h->bs + size);
403 memcpy (h->buf + h->bs, data, size);
404 h->bs += size;
405
406 dispatch_ready:
407 if (BUFFER_SIZE == fit_size)
408 dispatch_buffer (h);
409}
410
411
412/**
413 * Task to be executed when flushing our local buffer takes longer than timeout
414 * given to GNUNET_TESTBED_LOGGER_flush(). The flush completion callback will
415 * be called with 0 as the amount of data sent.
416 *
417 * @param cls the logger handle
418 */
419static void
420timeout_flush (void *cls)
421{
422 struct GNUNET_TESTBED_LOGGER_Handle *h = cls;
423 GNUNET_TESTBED_LOGGER_FlushCompletion cb;
424 void *cb_cls;
425
426 h->timeout_flush_task = NULL;
427 cb = h->cb;
428 h->cb = NULL;
429 cb_cls = h->cb_cls;
430 h->cb_cls = NULL;
431 if (NULL != h->flush_completion_task)
432 {
433 GNUNET_SCHEDULER_cancel (h->flush_completion_task);
434 h->flush_completion_task = NULL;
435 }
436 if (NULL != cb)
437 cb (cb_cls, 0);
438}
439
440
441/**
442 * Flush the buffered data to the logger service
443 *
444 * @param h the logger handle
445 * @param timeout how long to wait before calling the flust completion callback
446 * @param cb the callback to call after the data is flushed
447 * @param cb_cls the closure for the above callback
448 */
449void
450GNUNET_TESTBED_LOGGER_flush (struct GNUNET_TESTBED_LOGGER_Handle *h,
451 struct GNUNET_TIME_Relative timeout,
452 GNUNET_TESTBED_LOGGER_FlushCompletion cb,
453 void *cb_cls)
454{
455 h->cb = cb;
456 h->cb_cls = cb_cls;
457 GNUNET_assert (NULL == h->timeout_flush_task);
458 h->timeout_flush_task =
459 GNUNET_SCHEDULER_add_delayed (timeout, &timeout_flush, h);
460 if (NULL == h->buf)
461 {
462 trigger_flush_notification (h);
463 return;
464 }
465 dispatch_buffer (h);
466}
467
468
469/**
470 * Cancel notification upon flush. Should only be used when the flush
471 * completion callback given to GNUNET_TESTBED_LOGGER_flush() is not already
472 * called.
473 *
474 * @param h the logger handle
475 */
476void
477GNUNET_TESTBED_LOGGER_flush_cancel (struct GNUNET_TESTBED_LOGGER_Handle *h)
478{
479 if (NULL != h->flush_completion_task)
480 {
481 GNUNET_SCHEDULER_cancel (h->flush_completion_task);
482 h->flush_completion_task = NULL;
483 }
484 if (NULL != h->timeout_flush_task)
485 cancel_timeout_flush (h);
486 h->cb = NULL;
487 h->cb_cls = NULL;
488}
489
490/* End of testbed_logger_api.c */