summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/Makefile.am1
-rw-r--r--src/include/gnunet_mst_lib.h162
-rw-r--r--src/include/gnunet_util_lib.h1
-rw-r--r--src/util/Makefile.am1
-rw-r--r--src/util/mst.c363
-rw-r--r--src/util/service_new.c23
6 files changed, 531 insertions, 20 deletions
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 45cb6e5c6..866a90bef 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -71,6 +71,7 @@ gnunetinclude_HEADERS = \
71 gnunet_cadet_service.h \ 71 gnunet_cadet_service.h \
72 gnunet_microphone_lib.h \ 72 gnunet_microphone_lib.h \
73 gnunet_multicast_service.h \ 73 gnunet_multicast_service.h \
74 gnunet_mst_lib.h \
74 gnunet_mq_lib.h \ 75 gnunet_mq_lib.h \
75 gnunet_my_lib.h \ 76 gnunet_my_lib.h \
76 gnunet_mysql_lib.h \ 77 gnunet_mysql_lib.h \
diff --git a/src/include/gnunet_mst_lib.h b/src/include/gnunet_mst_lib.h
new file mode 100644
index 000000000..7a1ca7a55
--- /dev/null
+++ b/src/include/gnunet_mst_lib.h
@@ -0,0 +1,162 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016 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 * @author Christian Grothoff
23 *
24 * @file
25 * Library for tokenizing a message stream
26
27 * @defgroup server Server library
28 * Library for tokenizing a message stream
29 *
30 * @see [Documentation](https://gnunet.org/mst)
31 *
32 * @{
33 */
34
35#ifndef GNUNET_MST_LIB_H
36#define GNUNET_MST_LIB_H
37
38#ifdef __cplusplus
39extern "C"
40{
41#if 0 /* keep Emacsens' auto-indent happy */
42}
43#endif
44#endif
45
46#include "gnunet_common.h"
47
48
49/**
50 * Handle to a message stream tokenizer.
51 */
52struct GNUNET_MessageStreamTokenizer;
53
54
55/**
56 * Functions with this signature are called whenever a
57 * complete message is received by the tokenizer.
58 *
59 * Do not call #GNUNET_mst_destroy from within
60 * the scope of this callback.
61 *
62 * @param cls closure
63 * @param message the actual message
64 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
65 */
66typedef int
67(*GNUNET_MessageTokenizerCallback) (void *cls,
68 const struct GNUNET_MessageHeader *message);
69
70
71/**
72 * Create a message stream tokenizer.
73 *
74 * @param cb function to call on completed messages
75 * @param cb_cls closure for @a cb
76 * @return handle to tokenizer
77 */
78struct GNUNET_MessageStreamTokenizer *
79GNUNET_MST_create (GNUNET_MessageTokenizerCallback cb,
80 void *cb_cls);
81
82
83/**
84 * Add incoming data to the receive buffer and call the
85 * callback for all complete messages.
86 *
87 * @param mst tokenizer to use
88 * @param buf input data to add
89 * @param size number of bytes in @a buf
90 * @param purge should any excess bytes in the buffer be discarded
91 * (i.e. for packet-based services like UDP)
92 * @param one_shot only call callback once, keep rest of message in buffer
93 * @return #GNUNET_OK if we are done processing (need more data)
94 * #GNUNET_NO if one_shot was set and we have another message ready
95 * #GNUNET_SYSERR if the data stream is corrupt
96 */
97int
98GNUNET_MST_from_buffer (struct GNUNET_MessageStreamTokenizer *mst,
99 const char *buf,
100 size_t size,
101 int purge,
102 int one_shot);
103
104
105/**
106 * Add incoming data to the receive buffer and call the
107 * callback for all complete messages.
108 *
109 * @param mst tokenizer to use
110 * @param buf input data to add
111 * @param size number of bytes in @a buf
112 * @param purge should any excess bytes in the buffer be discarded
113 * (i.e. for packet-based services like UDP)
114 * @param one_shot only call callback once, keep rest of message in buffer
115 * @return #GNUNET_OK if we are done processing (need more data)
116 * #GNUNET_NO if one_shot was set and we have another message ready
117 * #GNUNET_SYSERR if the data stream is corrupt
118 */
119int
120GNUNET_MST_read (struct GNUNET_MessageStreamTokenizer *mst,
121 struct GNUNET_NETWORK_Handle *sock,
122 int purge,
123 int one_shot);
124
125
126/**
127 * Obtain the next message from the @a mst, assuming that
128 * there are more unprocessed messages in the internal buffer
129 * of the @a mst.
130 *
131 * @param mst tokenizer to use
132 * @param one_shot only call callback once, keep rest of message in buffer
133 * @return #GNUNET_OK if we are done processing (need more data)
134 * #GNUNET_NO if one_shot was set and we have another message ready
135 * #GNUNET_SYSERR if the data stream is corrupt
136 */
137int
138GNUNET_MST_next (struct GNUNET_MessageStreamTokenizer *mst,
139 int one_shot);
140
141
142/**
143 * Destroys a tokenizer.
144 *
145 * @param mst tokenizer to destroy
146 */
147void
148GNUNET_MST_destroy (struct GNUNET_MessageStreamTokenizer *mst);
149
150
151#if 0 /* keep Emacsens' auto-indent happy */
152{
153#endif
154#ifdef __cplusplus
155}
156#endif
157
158#endif
159
160/** @} */ /* end of group server */
161
162/* end of gnunet_mst_lib.h */
diff --git a/src/include/gnunet_util_lib.h b/src/include/gnunet_util_lib.h
index 599a04c0f..f0d964296 100644
--- a/src/include/gnunet_util_lib.h
+++ b/src/include/gnunet_util_lib.h
@@ -47,6 +47,7 @@ extern "C"
47#include "gnunet_container_lib.h" 47#include "gnunet_container_lib.h"
48#include "gnunet_getopt_lib.h" 48#include "gnunet_getopt_lib.h"
49#include "gnunet_helper_lib.h" 49#include "gnunet_helper_lib.h"
50#include "gnunet_mst_lib.h"
50#include "gnunet_mq_lib.h" 51#include "gnunet_mq_lib.h"
51#include "gnunet_op_lib.h" 52#include "gnunet_op_lib.h"
52#include "gnunet_os_lib.h" 53#include "gnunet_os_lib.h"
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index d6c93cefb..6822d539d 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -92,6 +92,7 @@ libgnunetutil_la_SOURCES = \
92 getopt_helpers.c \ 92 getopt_helpers.c \
93 helper.c \ 93 helper.c \
94 load.c \ 94 load.c \
95 mst.c \
95 mq.c \ 96 mq.c \
96 network.c \ 97 network.c \
97 op.c \ 98 op.c \
diff --git a/src/util/mst.c b/src/util/mst.c
new file mode 100644
index 000000000..578ba8e04
--- /dev/null
+++ b/src/util/mst.c
@@ -0,0 +1,363 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2016 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 util/mst.c
23 * @brief convenience functions for handling inbound message buffers
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30
31#if HAVE_UNALIGNED_64_ACCESS
32#define ALIGN_FACTOR 4
33#else
34#define ALIGN_FACTOR 8
35#endif
36
37#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
38
39
40/**
41 * Handle to a message stream tokenizer.
42 */
43struct GNUNET_MessageStreamTokenizer
44{
45
46 /**
47 * Function to call on completed messages.
48 */
49 GNUNET_MessageTokenizerCallback cb;
50
51 /**
52 * Closure for @e cb.
53 */
54 void *cb_cls;
55
56 /**
57 * Size of the buffer (starting at @e hdr).
58 */
59 size_t curr_buf;
60
61 /**
62 * How many bytes in buffer have we already processed?
63 */
64 size_t off;
65
66 /**
67 * How many bytes in buffer are valid right now?
68 */
69 size_t pos;
70
71 /**
72 * Beginning of the buffer. Typed like this to force alignment.
73 */
74 struct GNUNET_MessageHeader *hdr;
75
76};
77
78
79/**
80 * Create a message stream tokenizer.
81 *
82 * @param cb function to call on completed messages
83 * @param cb_cls closure for @a cb
84 * @return handle to tokenizer
85 */
86struct GNUNET_MessageStreamTokenizer *
87GNUNET_MST_create (GNUNET_MessageTokenizerCallback cb,
88 void *cb_cls)
89{
90 struct GNUNET_MessageStreamTokenizer *ret;
91
92 ret = GNUNET_new (struct GNUNET_MessageStreamTokenizer);
93 ret->hdr = GNUNET_malloc (GNUNET_SERVER_MIN_BUFFER_SIZE);
94 ret->curr_buf = GNUNET_SERVER_MIN_BUFFER_SIZE;
95 ret->cb = cb;
96 ret->cb_cls = cb_cls;
97 return ret;
98}
99
100
101/**
102 * Add incoming data to the receive buffer and call the
103 * callback for all complete messages.
104 *
105 * @param mst tokenizer to use
106 * @param buf input data to add
107 * @param size number of bytes in @a buf
108 * @param purge should any excess bytes in the buffer be discarded
109 * (i.e. for packet-based services like UDP)
110 * @param one_shot only call callback once, keep rest of message in buffer
111 * @return #GNUNET_OK if we are done processing (need more data)
112 * #GNUNET_NO if @a one_shot was set and we have another message ready
113 * #GNUNET_SYSERR if the data stream is corrupt
114 */
115int
116GNUNET_MST_from_buffer (struct GNUNET_MessageStreamTokenizer *mst,
117 const char *buf,
118 size_t size,
119 int purge,
120 int one_shot)
121{
122 const struct GNUNET_MessageHeader *hdr;
123 size_t delta;
124 uint16_t want;
125 char *ibuf;
126 int need_align;
127 unsigned long offset;
128 int ret;
129
130 GNUNET_assert (mst->off <= mst->pos);
131 GNUNET_assert (mst->pos <= mst->curr_buf);
132 LOG (GNUNET_ERROR_TYPE_DEBUG,
133 "Server-mst receives %u bytes with %u bytes already in private buffer\n",
134 (unsigned int) size,
135 (unsigned int) (mst->pos - mst->off));
136 ret = GNUNET_OK;
137 ibuf = (char *) mst->hdr;
138 while (mst->pos > 0)
139 {
140do_align:
141 GNUNET_assert (mst->pos >= mst->off);
142 if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) ||
143 (0 != (mst->off % ALIGN_FACTOR)))
144 {
145 /* need to align or need more space */
146 mst->pos -= mst->off;
147 memmove (ibuf, &ibuf[mst->off], mst->pos);
148 mst->off = 0;
149 }
150 if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
151 {
152 delta =
153 GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) -
154 (mst->pos - mst->off), size);
155 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
156 mst->pos += delta;
157 buf += delta;
158 size -= delta;
159 }
160 if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
161 {
162 if (purge)
163 {
164 mst->off = 0;
165 mst->pos = 0;
166 }
167 return GNUNET_OK;
168 }
169 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
170 want = ntohs (hdr->size);
171 if (want < sizeof (struct GNUNET_MessageHeader))
172 {
173 GNUNET_break_op (0);
174 return GNUNET_SYSERR;
175 }
176 if ( (mst->curr_buf - mst->off < want) &&
177 (mst->off > 0) )
178 {
179 /* can get more space by moving */
180 mst->pos -= mst->off;
181 memmove (ibuf, &ibuf[mst->off], mst->pos);
182 mst->off = 0;
183 }
184 if (mst->curr_buf < want)
185 {
186 /* need to get more space by growing buffer */
187 GNUNET_assert (0 == mst->off);
188 mst->hdr = GNUNET_realloc (mst->hdr, want);
189 ibuf = (char *) mst->hdr;
190 mst->curr_buf = want;
191 }
192 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
193 if (mst->pos - mst->off < want)
194 {
195 delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
196 GNUNET_assert (mst->pos + delta <= mst->curr_buf);
197 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
198 mst->pos += delta;
199 buf += delta;
200 size -= delta;
201 }
202 if (mst->pos - mst->off < want)
203 {
204 if (purge)
205 {
206 mst->off = 0;
207 mst->pos = 0;
208 }
209 return GNUNET_OK;
210 }
211 if (one_shot == GNUNET_SYSERR)
212 {
213 /* cannot call callback again, but return value saying that
214 * we have another full message in the buffer */
215 ret = GNUNET_NO;
216 goto copy;
217 }
218 if (one_shot == GNUNET_YES)
219 one_shot = GNUNET_SYSERR;
220 mst->off += want;
221 if (GNUNET_SYSERR == mst->cb (mst->cb_cls,
222 hdr))
223 return GNUNET_SYSERR;
224 if (mst->off == mst->pos)
225 {
226 /* reset to beginning of buffer, it's free right now! */
227 mst->off = 0;
228 mst->pos = 0;
229 }
230 }
231 GNUNET_assert (0 == mst->pos);
232 while (size > 0)
233 {
234 LOG (GNUNET_ERROR_TYPE_DEBUG,
235 "Server-mst has %u bytes left in inbound buffer\n",
236 (unsigned int) size);
237 if (size < sizeof (struct GNUNET_MessageHeader))
238 break;
239 offset = (unsigned long) buf;
240 need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO;
241 if (GNUNET_NO == need_align)
242 {
243 /* can try to do zero-copy and process directly from original buffer */
244 hdr = (const struct GNUNET_MessageHeader *) buf;
245 want = ntohs (hdr->size);
246 if (want < sizeof (struct GNUNET_MessageHeader))
247 {
248 GNUNET_break_op (0);
249 mst->off = 0;
250 return GNUNET_SYSERR;
251 }
252 if (size < want)
253 break; /* or not: buffer incomplete, so copy to private buffer... */
254 if (one_shot == GNUNET_SYSERR)
255 {
256 /* cannot call callback again, but return value saying that
257 * we have another full message in the buffer */
258 ret = GNUNET_NO;
259 goto copy;
260 }
261 if (one_shot == GNUNET_YES)
262 one_shot = GNUNET_SYSERR;
263 if (GNUNET_SYSERR == mst->cb (mst->cb_cls,
264 hdr))
265 return GNUNET_SYSERR;
266 buf += want;
267 size -= want;
268 }
269 else
270 {
271 /* need to copy to private buffer to align;
272 * yes, we go a bit more spagetti than usual here */
273 goto do_align;
274 }
275 }
276copy:
277 if ((size > 0) && (!purge))
278 {
279 if (size + mst->pos > mst->curr_buf)
280 {
281 mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos);
282 ibuf = (char *) mst->hdr;
283 mst->curr_buf = size + mst->pos;
284 }
285 GNUNET_assert (size + mst->pos <= mst->curr_buf);
286 GNUNET_memcpy (&ibuf[mst->pos], buf, size);
287 mst->pos += size;
288 }
289 if (purge)
290 {
291 mst->off = 0;
292 mst->pos = 0;
293 }
294 LOG (GNUNET_ERROR_TYPE_DEBUG,
295 "Server-mst leaves %u bytes in private buffer\n",
296 (unsigned int) (mst->pos - mst->off));
297 return ret;
298}
299
300
301/**
302 * Add incoming data to the receive buffer and call the
303 * callback for all complete messages.
304 *
305 * @param mst tokenizer to use
306 * @param buf input data to add
307 * @param size number of bytes in @a buf
308 * @param purge should any excess bytes in the buffer be discarded
309 * (i.e. for packet-based services like UDP)
310 * @param one_shot only call callback once, keep rest of message in buffer
311 * @return #GNUNET_OK if we are done processing (need more data)
312 * #GNUNET_NO if one_shot was set and we have another message ready
313 * #GNUNET_SYSERR if the data stream is corrupt
314 */
315int
316GNUNET_MST_read (struct GNUNET_MessageStreamTokenizer *mst,
317 struct GNUNET_NETWORK_Handle *sock,
318 int purge,
319 int one_shot)
320{
321 GNUNET_assert (0); // not implemented
322 return GNUNET_SYSERR;
323}
324
325
326/**
327 * Obtain the next message from the @a mst, assuming that
328 * there are more unprocessed messages in the internal buffer
329 * of the @a mst.
330 *
331 * @param mst tokenizer to use
332 * @param one_shot only call callback once, keep rest of message in buffer
333 * @return #GNUNET_OK if we are done processing (need more data)
334 * #GNUNET_NO if one_shot was set and we have another message ready
335 * #GNUNET_SYSERR if the data stream is corrupt
336 */
337int
338GNUNET_MST_next (struct GNUNET_MessageStreamTokenizer *mst,
339 int one_shot)
340{
341 return GNUNET_MST_from_buffer (mst,
342 NULL,
343 0,
344 GNUNET_NO,
345 one_shot);
346}
347
348
349/**
350 * Destroys a tokenizer.
351 *
352 * @param mst tokenizer to destroy
353 */
354void
355GNUNET_MST_destroy (struct GNUNET_MessageStreamTokenizer *mst)
356{
357 GNUNET_free (mst->hdr);
358 GNUNET_free (mst);
359}
360
361
362
363/* end of server_mst.c */
diff --git a/src/util/service_new.c b/src/util/service_new.c
index fc47289f6..34f96a598 100644
--- a/src/util/service_new.c
+++ b/src/util/service_new.c
@@ -447,24 +447,6 @@ service_mq_send (struct GNUNET_MQ_Handle *mq,
447 447
448 448
449/** 449/**
450 * Implements the destruction of a message queue. Implementations
451 * must not free @a mq, but should take care of @a impl_state.
452 * Not sure there is anything to do here! (FIXME!)
453 *
454 * @param mq the message queue to destroy
455 * @param impl_state state of the implementation
456 */
457static void
458service_mq_destroy (struct GNUNET_MQ_Handle *mq,
459 void *impl_state)
460{
461 struct GNUNET_SERVICE_Client *client = cls;
462
463 // FIXME
464}
465
466
467/**
468 * Implementation function that cancels the currently sent message. 450 * Implementation function that cancels the currently sent message.
469 * 451 *
470 * @param mq message queue 452 * @param mq message queue
@@ -476,7 +458,8 @@ service_mq_cancel (struct GNUNET_MQ_Handle *mq,
476{ 458{
477 struct GNUNET_SERVICE_Client *client = cls; 459 struct GNUNET_SERVICE_Client *client = cls;
478 460
479 // FIXME: semantics? What to do!? 461 // FIXME: stop transmission! (must be possible, otherwise
462 // we must have told MQ that the message was sent!)
480} 463}
481 464
482 465
@@ -561,7 +544,7 @@ start_client (struct GNUNET_SERVICE_Handle *sh,
561 client->sh = sh; 544 client->sh = sh;
562 client->sock = csock; 545 client->sock = csock;
563 client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send, 546 client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send,
564 &service_mq_destroy, 547 NULL,
565 &service_mq_cancel, 548 &service_mq_cancel,
566 client, 549 client,
567 sh->handlers, 550 sh->handlers,