GNUnet  0.10.x
tcp_server_mst_legacy.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your 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  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19 */
20 
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 
42 {
43 
48 
52  void *cb_cls;
53 
57  size_t curr_buf;
58 
62  size_t off;
63 
67  size_t pos;
68 
73 
74 };
75 
76 
77 
87  void *cb_cls)
88 {
90 
94  ret->cb = cb;
95  ret->cb_cls = cb_cls;
96  return ret;
97 }
98 
99 
115 int
117  void *client_identity,
118  const char *buf, size_t size,
119  int purge, int one_shot)
120 {
121  const struct GNUNET_MessageHeader *hdr;
122  size_t delta;
123  uint16_t want;
124  char *ibuf;
125  int need_align;
126  unsigned long offset;
127  int ret;
128 
129  GNUNET_assert (mst->off <= mst->pos);
130  GNUNET_assert (mst->pos <= mst->curr_buf);
132  "Server-mst receives %u bytes with %u bytes already in private buffer\n",
133  (unsigned int) size, (unsigned int) (mst->pos - mst->off));
134  ret = GNUNET_OK;
135  ibuf = (char *) mst->hdr;
136  while (mst->pos > 0)
137  {
138 do_align:
139  GNUNET_assert (mst->pos >= mst->off);
140  if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) ||
141  (0 != (mst->off % ALIGN_FACTOR)))
142  {
143  /* need to align or need more space */
144  mst->pos -= mst->off;
145  memmove (ibuf, &ibuf[mst->off], mst->pos);
146  mst->off = 0;
147  }
148  if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
149  {
150  delta =
151  GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) -
152  (mst->pos - mst->off), size);
153  GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
154  mst->pos += delta;
155  buf += delta;
156  size -= delta;
157  }
158  if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
159  {
160  if (purge)
161  {
162  mst->off = 0;
163  mst->pos = 0;
164  }
165  return GNUNET_OK;
166  }
167  hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
168  want = ntohs (hdr->size);
169  if (want < sizeof (struct GNUNET_MessageHeader))
170  {
171  GNUNET_break_op (0);
172  return GNUNET_SYSERR;
173  }
174  if ( (mst->curr_buf - mst->off < want) &&
175  (mst->off > 0) )
176  {
177  /* can get more space by moving */
178  mst->pos -= mst->off;
179  memmove (ibuf, &ibuf[mst->off], mst->pos);
180  mst->off = 0;
181  }
182  if (mst->curr_buf < want)
183  {
184  /* need to get more space by growing buffer */
185  GNUNET_assert (0 == mst->off);
186  mst->hdr = GNUNET_realloc (mst->hdr, want);
187  ibuf = (char *) mst->hdr;
188  mst->curr_buf = want;
189  }
190  hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
191  if (mst->pos - mst->off < want)
192  {
193  delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
194  GNUNET_assert (mst->pos + delta <= mst->curr_buf);
195  GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
196  mst->pos += delta;
197  buf += delta;
198  size -= delta;
199  }
200  if (mst->pos - mst->off < want)
201  {
202  if (purge)
203  {
204  mst->off = 0;
205  mst->pos = 0;
206  }
207  return GNUNET_OK;
208  }
209  if (one_shot == GNUNET_SYSERR)
210  {
211  /* cannot call callback again, but return value saying that
212  * we have another full message in the buffer */
213  ret = GNUNET_NO;
214  goto copy;
215  }
216  if (one_shot == GNUNET_YES)
217  one_shot = GNUNET_SYSERR;
218  mst->off += want;
219  if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
220  return GNUNET_SYSERR;
221  if (mst->off == mst->pos)
222  {
223  /* reset to beginning of buffer, it's free right now! */
224  mst->off = 0;
225  mst->pos = 0;
226  }
227  }
228  GNUNET_assert (0 == mst->pos);
229  while (size > 0)
230  {
232  "Server-mst has %u bytes left in inbound buffer\n",
233  (unsigned int) size);
234  if (size < sizeof (struct GNUNET_MessageHeader))
235  break;
236  offset = (unsigned long) buf;
237  need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO;
238  if (GNUNET_NO == need_align)
239  {
240  /* can try to do zero-copy and process directly from original buffer */
241  hdr = (const struct GNUNET_MessageHeader *) buf;
242  want = ntohs (hdr->size);
243  if (want < sizeof (struct GNUNET_MessageHeader))
244  {
245  GNUNET_break_op (0);
246  mst->off = 0;
247  return GNUNET_SYSERR;
248  }
249  if (size < want)
250  break; /* or not: buffer incomplete, so copy to private buffer... */
251  if (one_shot == GNUNET_SYSERR)
252  {
253  /* cannot call callback again, but return value saying that
254  * we have another full message in the buffer */
255  ret = GNUNET_NO;
256  goto copy;
257  }
258  if (one_shot == GNUNET_YES)
259  one_shot = GNUNET_SYSERR;
260  if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
261  return GNUNET_SYSERR;
262  buf += want;
263  size -= want;
264  }
265  else
266  {
267  /* need to copy to private buffer to align;
268  * yes, we go a bit more spagetti than usual here */
269  goto do_align;
270  }
271  }
272 copy:
273  if ((size > 0) && (!purge))
274  {
275  if (size + mst->pos > mst->curr_buf)
276  {
277  mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos);
278  ibuf = (char *) mst->hdr;
279  mst->curr_buf = size + mst->pos;
280  }
281  GNUNET_assert (size + mst->pos <= mst->curr_buf);
282  GNUNET_memcpy (&ibuf[mst->pos], buf, size);
283  mst->pos += size;
284  }
285  if (purge)
286  {
287  mst->off = 0;
288  mst->pos = 0;
289  }
291  "Server-mst leaves %u bytes in private buffer\n",
292  (unsigned int) (mst->pos - mst->off));
293  return ret;
294 }
295 
296 
302 void
304 {
305  GNUNET_free (mst->hdr);
306  GNUNET_free (mst);
307 }
308 
309 
310 
311 /* end of server_mst.c */
static struct GNUNET_TIME_Relative delta
Definition: speedup.c:35
#define ALIGN_FACTOR
static size_t do_align(size_t start_position, size_t end_position)
Given the start and end position of a block of data, return the end position of that data after align...
Definition: fs_directory.c:484
#define LOG(kind,...)
Definition: arm_api.c:33
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
struct GNUNET_SERVER_MessageStreamTokenizer * GNUNET_SERVER_mst_create(GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
#define GNUNET_NO
Definition: gnunet_common.h:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
#define GNUNET_new(type)
Allocate a struct or union of the given type.
int GNUNET_SERVER_mst_receive(struct GNUNET_SERVER_MessageStreamTokenizer *mst, void *client_identity, const char *buf, size_t size, int purge, int one_shot)
Add incoming data to the receive buffer and call the callback for all complete messages.
size_t pos
How many bytes in buffer are valid right now?
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
static int ret
Final status code.
Definition: gnunet-arm.c:89
int(* GNUNET_SERVER_MessageTokenizerCallback)(void *cls, void *client, const struct GNUNET_MessageHeader *message)
Functions with this signature are called whenever a complete message is received by the tokenizer...
size_t off
How many bytes in buffer have we already processed?
Handle to a message stream tokenizer.
#define GNUNET_memcpy(dst, src, n)
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.
#define GNUNET_MIN(a, b)
Definition: gnunet_common.h:83
static char buf[2048]
#define GNUNET_MIN_MESSAGE_SIZE
Smallest supported message.
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
static unsigned int size
Size of the "table".
Definition: peer.c:67
struct GNUNET_MessageHeader * hdr
Beginning of the buffer.
GNUNET_SERVER_MessageTokenizerCallback cb
Function to call on completed messages.
size_t curr_buf
Size of the buffer (starting at hdr).
void GNUNET_SERVER_mst_destroy(struct GNUNET_SERVER_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Header for all communications.
#define GNUNET_YES
Definition: gnunet_common.h:80
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.