aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLRN <lrn1986@gmail.com>2014-01-08 14:14:41 +0000
committerLRN <lrn1986@gmail.com>2014-01-08 14:14:41 +0000
commit39d0485fb4ec8cb5b3142c86130b276ed455cb65 (patch)
tree3adbcbcb6581eb804b4cde216a077d987a91b64a /src
parent0d2a0bf33883e452dd988a5b173428161e38b4af (diff)
downloadgnunet-39d0485fb4ec8cb5b3142c86130b276ed455cb65.tar.gz
gnunet-39d0485fb4ec8cb5b3142c86130b276ed455cb65.zip
Add console hackery for gnunet-conversation on W32
Diffstat (limited to 'src')
-rw-r--r--src/conversation/gnunet-conversation.c132
-rw-r--r--src/util/Makefile.am12
-rwxr-xr-xsrc/util/gnunet-helper-w32-console.c318
-rwxr-xr-xsrc/util/gnunet-helper-w32-console.h72
4 files changed, 511 insertions, 23 deletions
diff --git a/src/conversation/gnunet-conversation.c b/src/conversation/gnunet-conversation.c
index a042629cc..3cb6cc05f 100644
--- a/src/conversation/gnunet-conversation.c
+++ b/src/conversation/gnunet-conversation.c
@@ -29,13 +29,25 @@
29#include "gnunet_gnsrecord_lib.h" 29#include "gnunet_gnsrecord_lib.h"
30#include "gnunet_conversation_service.h" 30#include "gnunet_conversation_service.h"
31#include "gnunet_namestore_service.h" 31#include "gnunet_namestore_service.h"
32 32#ifdef WINDOWS
33#include "../util/gnunet-helper-w32-console.h"
34#endif
33 35
34/** 36/**
35 * Maximum length allowed for the command line input. 37 * Maximum length allowed for the command line input.
36 */ 38 */
37#define MAX_MESSAGE_LENGTH 1024 39#define MAX_MESSAGE_LENGTH 1024
38 40
41#define XSTRINGIFY(x) STRINGIFY(x)
42
43#define STRINGIFY(x) (#x)
44
45#ifdef WINDOWS
46/**
47 * Helper that reads the console for us.
48 */
49struct GNUNET_HELPER_Handle *stdin_hlp;
50#endif
39 51
40/** 52/**
41 * Possible states of the phone. 53 * Possible states of the phone.
@@ -997,6 +1009,13 @@ static void
997do_stop_task (void *cls, 1009do_stop_task (void *cls,
998 const struct GNUNET_SCHEDULER_TaskContext *tc) 1010 const struct GNUNET_SCHEDULER_TaskContext *tc)
999{ 1011{
1012#ifdef WINDOWS
1013 if (NULL != stdin_hlp)
1014 {
1015 GNUNET_HELPER_stop (stdin_hlp, GNUNET_NO);
1016 stdin_hlp = NULL;
1017 }
1018#endif
1000 if (NULL != call) 1019 if (NULL != call)
1001 { 1020 {
1002 GNUNET_CONVERSATION_call_stop (call); 1021 GNUNET_CONVERSATION_call_stop (call);
@@ -1027,6 +1046,60 @@ do_stop_task (void *cls,
1027 phone_state = PS_ERROR; 1046 phone_state = PS_ERROR;
1028} 1047}
1029 1048
1049static void
1050handle_command_string (char *message, size_t str_len)
1051{
1052 size_t i;
1053 const char *ptr;
1054
1055 if (0 == str_len)
1056 return;
1057 if (message[str_len - 1] == '\n')
1058 message[str_len - 1] = '\0';
1059 if (message[str_len - 2] == '\r')
1060 message[str_len - 2] = '\0';
1061 if (0 == strlen (message))
1062 return;
1063 i = 0;
1064 while ((NULL != commands[i].command) &&
1065 (0 != strncasecmp (commands[i].command, message,
1066 strlen (commands[i].command))))
1067 i++;
1068 ptr = &message[strlen (commands[i].command)];
1069 while (isspace ((int) *ptr))
1070 ptr++;
1071 if ('\0' == *ptr)
1072 ptr = NULL;
1073 commands[i].Action (ptr);
1074}
1075
1076
1077#ifdef WINDOWS
1078int
1079console_reader_chars (void *cls, void *client,
1080 const struct GNUNET_MessageHeader *message)
1081{
1082 char *chars;
1083 size_t str_size;
1084 switch (ntohs (message->type))
1085 {
1086 case GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_CHARS:
1087 chars = (char *) &message[1];
1088 str_size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader);
1089 if (chars[str_size - 1] != '\0')
1090 return GNUNET_SYSERR;
1091 /* FIXME: is it ok that we pass part of a const struct to
1092 * this function that may mangle the contents?
1093 */
1094 handle_command_string (chars, str_size - 1);
1095 break;
1096 default:
1097 GNUNET_break (0);
1098 break;
1099 }
1100 return GNUNET_OK;
1101}
1102#endif
1030 1103
1031/** 1104/**
1032 * Task to handle commands from the terminal. 1105 * Task to handle commands from the terminal.
@@ -1039,8 +1112,6 @@ handle_command (void *cls,
1039 const struct GNUNET_SCHEDULER_TaskContext *tc) 1112 const struct GNUNET_SCHEDULER_TaskContext *tc)
1040{ 1113{
1041 char message[MAX_MESSAGE_LENGTH + 1]; 1114 char message[MAX_MESSAGE_LENGTH + 1];
1042 const char *ptr;
1043 size_t i;
1044 1115
1045 handle_cmd_task = 1116 handle_cmd_task =
1046 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, 1117 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
@@ -1050,23 +1121,7 @@ handle_command (void *cls,
1050 memset (message, 0, MAX_MESSAGE_LENGTH + 1); 1121 memset (message, 0, MAX_MESSAGE_LENGTH + 1);
1051 if (NULL == fgets (message, MAX_MESSAGE_LENGTH, stdin)) 1122 if (NULL == fgets (message, MAX_MESSAGE_LENGTH, stdin))
1052 return; 1123 return;
1053 if (0 == strlen (message)) 1124 handle_command_string (message, strlen (message));
1054 return;
1055 if (message[strlen (message) - 1] == '\n')
1056 message[strlen (message) - 1] = '\0';
1057 if (0 == strlen (message))
1058 return;
1059 i = 0;
1060 while ((NULL != commands[i].command) &&
1061 (0 != strncasecmp (commands[i].command, message,
1062 strlen (commands[i].command))))
1063 i++;
1064 ptr = &message[strlen (commands[i].command)];
1065 while (isspace ((int) *ptr))
1066 ptr++;
1067 if ('\0' == *ptr)
1068 ptr = NULL;
1069 commands[i].Action (ptr);
1070} 1125}
1071 1126
1072 1127
@@ -1144,6 +1199,30 @@ run (void *cls,
1144 id = GNUNET_IDENTITY_connect (cfg, 1199 id = GNUNET_IDENTITY_connect (cfg,
1145 &identity_cb, 1200 &identity_cb,
1146 NULL); 1201 NULL);
1202#ifdef WINDOWS
1203 if (stdin_fh == NULL)
1204 {
1205 static char cpid[64];
1206 static char *args[] = {"gnunet-helper-w32-console.exe", "chars",
1207 XSTRINGIFY (MAX_MESSAGE_LENGTH), cpid, NULL};
1208 snprintf (cpid, 64, "%d", GetCurrentProcessId ());
1209 stdin_hlp = GNUNET_HELPER_start (
1210 GNUNET_NO,
1211 "gnunet-helper-w32-console",
1212 args,
1213 console_reader_chars,
1214 NULL,
1215 NULL);
1216 if (NULL == stdin_hlp)
1217 {
1218 FPRINTF (stderr,
1219 "%s",
1220 _("Failed to start gnunet-helper-w32-console\n"));
1221 return;
1222 }
1223 }
1224 else
1225#endif
1147 handle_cmd_task = 1226 handle_cmd_task =
1148 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI, 1227 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI,
1149 &handle_command, NULL); 1228 &handle_command, NULL);
@@ -1171,13 +1250,22 @@ main (int argc, char *const *argv)
1171 1, &GNUNET_GETOPT_set_uint, &line}, 1250 1, &GNUNET_GETOPT_set_uint, &line},
1172 GNUNET_GETOPT_OPTION_END 1251 GNUNET_GETOPT_OPTION_END
1173 }; 1252 };
1174 int flags;
1175 int ret; 1253 int ret;
1176 1254#ifndef WINDOWS
1255 int flags;
1177 flags = fcntl (0, F_GETFL, 0); 1256 flags = fcntl (0, F_GETFL, 0);
1178 flags |= O_NONBLOCK; 1257 flags |= O_NONBLOCK;
1179 fcntl (0, F_SETFL, flags); 1258 fcntl (0, F_SETFL, flags);
1180 stdin_fh = GNUNET_DISK_get_handle_from_int_fd (0); 1259 stdin_fh = GNUNET_DISK_get_handle_from_int_fd (0);
1260#else
1261 if (FILE_TYPE_CHAR == GetFileType ((HANDLE) _get_osfhandle (0)))
1262 {
1263 stdin_fh = NULL;
1264 }
1265 else
1266 stdin_fh = GNUNET_DISK_get_handle_from_int_fd (0);
1267#endif
1268
1181 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 1269 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1182 return 2; 1270 return 2;
1183 ret = GNUNET_PROGRAM_run (argc, argv, 1271 ret = GNUNET_PROGRAM_run (argc, argv,
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index dcd2f9121..f8f6e2ede 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -25,6 +25,7 @@ libgnunetutilwin_la_LIBADD = \
25 -lcomdlg32 -lgdi32 -liphlpapi 25 -lcomdlg32 -lgdi32 -liphlpapi
26WINLIB = libgnunetutilwin.la 26WINLIB = libgnunetutilwin.la
27W32CAT = w32cat 27W32CAT = w32cat
28W32CONSOLEHELPER = gnunet-helper-w32-console
28endif 29endif
29 30
30if !MINGW 31if !MINGW
@@ -38,6 +39,14 @@ endif
38 39
39w32cat_SOURCES = w32cat.c 40w32cat_SOURCES = w32cat.c
40 41
42gnunet_helper_w32_console_SOURCES = \
43 gnunet-helper-w32-console.c \
44 gnunet-helper-w32-console.h
45gnunet_helper_w32_console_LDADD = \
46 $(top_builddir)/src/util/libgnunetutil.la
47gnunet_helper_w32_console_DEPENDENCIES = \
48 libgnunetutil.la
49
41noinst_PROGRAMS = \ 50noinst_PROGRAMS = \
42 gnunet-config-diff \ 51 gnunet-config-diff \
43 $(W32CAT) \ 52 $(W32CAT) \
@@ -126,7 +135,8 @@ endif
126 135
127 136
128libexec_PROGRAMS = \ 137libexec_PROGRAMS = \
129 gnunet-service-resolver 138 gnunet-service-resolver \
139 $(W32CONSOLEHELPER)
130 140
131bin_SCRIPTS =\ 141bin_SCRIPTS =\
132 gnunet-qr 142 gnunet-qr
diff --git a/src/util/gnunet-helper-w32-console.c b/src/util/gnunet-helper-w32-console.c
new file mode 100755
index 000000000..60ffbe018
--- /dev/null
+++ b/src/util/gnunet-helper-w32-console.c
@@ -0,0 +1,318 @@
1/*
2 This file is part of GNUnet.
3 (C) 2014 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file src/util/gnunet-helper-w32-console.c
23 * @brief Does blocking reads from the console, writes the results
24 * into stdout, turning blocking console I/O into non-blocking
25 * pipe I/O. For W32 only.
26 * @author LRN
27 */
28#include "platform.h"
29#include "gnunet_crypto_lib.h"
30#include "gnunet_common.h"
31#include "gnunet-helper-w32-console.h"
32
33static unsigned long buffer_size;
34
35static int chars;
36
37static HANDLE parent_handle;
38
39/**
40 * Write @a size bytes from @a buf into @a output.
41 *
42 * @param output the descriptor to write into
43 * @param buf buffer with data to write
44 * @param size number of bytes to write
45 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
46 */
47static int
48write_all (int output,
49 const void *buf,
50 size_t size)
51{
52 const char *cbuf = buf;
53 size_t total;
54 ssize_t wr;
55
56 total = 0;
57 do
58 {
59 wr = write (output,
60 &cbuf[total],
61 size - total);
62 if (wr > 0)
63 total += wr;
64 } while ( (wr > 0) && (total < size) );
65 if (wr <= 0)
66 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
67 "Failed to write to stdout: %s\n",
68 strerror (errno));
69 return (total == size) ? GNUNET_OK : GNUNET_SYSERR;
70}
71
72
73/**
74 * Write message to the master process.
75 *
76 * @param output the descriptor to write into
77 * @param message_type message type to use
78 * @param data data to append, NULL for none
79 * @param data_length number of bytes in @a data
80 * @return #GNUNET_SYSERR to stop scanning (the pipe was broken somehow)
81 */
82static int
83write_message (int output,
84 uint16_t message_type,
85 const char *data,
86 size_t data_length)
87{
88 struct GNUNET_MessageHeader hdr;
89
90#if 0
91 fprintf (stderr,
92 "Helper sends %u-byte message of type %u\n",
93 (unsigned int) (sizeof (struct GNUNET_MessageHeader) + data_length),
94 (unsigned int) message_type);
95#endif
96 hdr.type = htons (message_type);
97 hdr.size = htons (sizeof (struct GNUNET_MessageHeader) + data_length);
98 if (GNUNET_OK != write_all (output, &hdr, sizeof (hdr)))
99 return GNUNET_SYSERR;
100 if (GNUNET_OK != write_all (output, data, data_length))
101 return GNUNET_SYSERR;
102 return GNUNET_OK;
103}
104
105
106/**
107 * Main function of the helper process. Reads input events from console,
108 * writes messages, into stdout.
109 *
110 * @param console a handle to a console to read from
111 * @param output_stream a stream to write messages to
112 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
113 */
114static int
115read_events (HANDLE console, int output_stream)
116{
117 DWORD rr;
118 BOOL b;
119 INPUT_RECORD *buf;
120 DWORD i;
121 int result;
122
123 result = GNUNET_SYSERR;
124 buf = malloc (sizeof (INPUT_RECORD) * buffer_size);
125 if (NULL == buf)
126 return result;
127 b = TRUE;
128 rr = 1;
129 while (TRUE == b && 0 < rr)
130 {
131 rr = 0;
132 b = ReadConsoleInput (console, buf, buffer_size, &rr);
133 if (FALSE == b && ERROR_SUCCESS != GetLastError ())
134 break;
135 for (i = 0; i < rr; i++)
136 {
137 int r;
138 r = write_message (output_stream,
139 GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_INPUT,
140 (const char *) &buf[i],
141 sizeof (INPUT_RECORD));
142 if (GNUNET_OK != r)
143 break;
144 }
145 if (rr + 1 != i)
146 break;
147 }
148 return result;
149}
150
151
152/**
153 * Main function of the helper process. Reads chars from console,
154 * writes messages, into stdout.
155 *
156 * @param console a handle to a console to read from
157 * @param output_stream a stream to write messages to
158 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
159 */
160static int
161read_chars (HANDLE console, int output_stream)
162{
163 DWORD rr;
164 BOOL b;
165 wchar_t *buf;
166 char *small_ubuf;
167 char *large_ubuf;
168 char *ubuf;
169 int conv;
170 int r;
171 int result;
172
173 result = GNUNET_SYSERR;
174 buf = malloc (sizeof (wchar_t) * buffer_size);
175 if (NULL == buf)
176 return result;
177 small_ubuf = malloc (sizeof (char) * buffer_size * 2);
178 if (NULL == small_ubuf)
179 {
180 free (buf);
181 return result;
182 }
183 b = TRUE;
184 rr = 1;
185 while (TRUE == b)
186 {
187 large_ubuf = NULL;
188 rr = 0;
189 b = ReadConsoleW (console, buf, buffer_size, &rr, NULL);
190 if (FALSE == b && ERROR_SUCCESS != GetLastError ())
191 break;
192 if (0 == rr)
193 continue;
194 /* Caveat: if the UTF-16-encoded string is longer than BUFFER_SIZE,
195 * there's a possibility that we will read up to a word that constitutes
196 * a part of a multi-byte UTF-16 codepoint. Converting that to UTF-8
197 * will either drop invalid word (flags == 0) or bail out because of it
198 * (flags == WC_ERR_INVALID_CHARS).
199 */
200 conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, small_ubuf, 0, NULL, FALSE);
201 if (0 == conv || 0xFFFD == conv)
202 continue;
203 if (conv <= buffer_size * 2 - 1)
204 {
205 memset (small_ubuf, 0, buffer_size * 2);
206 conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, small_ubuf, buffer_size * 2 - 1, NULL, FALSE);
207 if (0 == conv || 0xFFFD == conv)
208 continue;
209 ubuf = small_ubuf;
210 }
211 else
212 {
213 large_ubuf = malloc (conv + 1);
214 if (NULL == large_ubuf)
215 continue;
216 memset (large_ubuf, 0, conv + 1);
217 conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, large_ubuf, conv, NULL, FALSE);
218 if (0 == conv || 0xFFFD == conv)
219 {
220 free (large_ubuf);
221 large_ubuf = NULL;
222 continue;
223 }
224 ubuf = large_ubuf;
225 }
226 r = write_message (output_stream,
227 GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_CHARS,
228 ubuf,
229 conv + 1);
230 if (large_ubuf)
231 free (large_ubuf);
232 if (GNUNET_OK != r)
233 break;
234 }
235 free (small_ubuf);
236 free (buf);
237 return result;
238}
239
240
241DWORD WINAPI
242watch_parent (LPVOID param)
243{
244 WaitForSingleObject (parent_handle, INFINITE);
245 ExitProcess (1);
246 return 0;
247}
248
249/**
250 * Main function of the helper process to extract meta data.
251 *
252 * @param argc should be 3
253 * @param argv [0] our binary name
254 * [1] name of the file or directory to process
255 * [2] "-" to disable extraction, NULL for defaults,
256 * otherwise custom plugins to load from LE
257 * @return 0 on success
258 */
259int
260main (int argc,
261 char *const *argv)
262{
263 HANDLE os_stdin;
264 DWORD parent_pid;
265 /* We're using stdout to communicate binary data back to the parent; use
266 * binary mode.
267 */
268 _setmode (1, _O_BINARY);
269
270 if (argc != 4)
271 {
272 fprintf (stderr,
273 "Usage: gnunet-helper-w32-console <chars|events> <buffer size> <parent pid>\n");
274 return 2;
275 }
276
277 if (0 == strcmp (argv[1], "chars"))
278 chars = GNUNET_YES;
279 else if (0 == strcmp (argv[1], "events"))
280 chars = GNUNET_NO;
281 else
282 return 3;
283
284 buffer_size = strtoul (argv[2], NULL, 10);
285 if (buffer_size <= 0)
286 return 4;
287
288 parent_pid = (DWORD) strtoul (argv[3], NULL, 10);
289 if (parent_pid == 0)
290 return 5;
291 parent_handle = OpenProcess (SYNCHRONIZE, FALSE, parent_pid);
292 if (NULL == parent_handle)
293 return 6;
294
295 CreateThread (NULL, 0, watch_parent, NULL, 0, NULL);
296
297 if (0 == AttachConsole (ATTACH_PARENT_PROCESS))
298 {
299 if (ERROR_ACCESS_DENIED != GetLastError ())
300 return 5;
301 }
302
303 /* Helper API overrides stdin, so we just attach to the console that we
304 * inherited. If we did.
305 */
306 os_stdin = CreateFile ("CONIN$", GENERIC_READ | GENERIC_WRITE,
307 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
308 if (INVALID_HANDLE_VALUE == os_stdin)
309 return 1;
310
311 if (GNUNET_NO == chars)
312 return read_events (os_stdin, 1);
313 else
314 return read_chars (os_stdin, 1);
315
316}
317
318/* end of gnunet-helper-w32-console.c */
diff --git a/src/util/gnunet-helper-w32-console.h b/src/util/gnunet-helper-w32-console.h
new file mode 100755
index 000000000..df5316cdf
--- /dev/null
+++ b/src/util/gnunet-helper-w32-console.h
@@ -0,0 +1,72 @@
1/*
2 This file is part of GNUnet.
3 (C) 2014 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @author LRN
23 * @file src/util/gnunet-helper-w32-console.h
24 */
25#ifndef GNUNET_HELPER_W32_CONSOLE_H
26#define GNUNET_HELPER_W32_CONSOLE_H
27
28#include "platform.h"
29#include "gnunet_crypto_lib.h"
30#include "gnunet_common.h"
31
32/**
33 * Input event from the console
34 */
35#define GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_INPUT 60000
36
37/**
38 * Chars from the console
39 */
40#define GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_CHARS 60001
41
42GNUNET_NETWORK_STRUCT_BEGIN
43
44/**
45 * This is just a dump of the INPUT_RECORD structure.
46 */
47struct GNUNET_W32_CONSOLE_input
48{
49 /**
50 * Type: GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_INPUT
51 */
52 struct GNUNET_MessageHeader header;
53
54 INPUT_RECORD input_record GNUNET_PACKED;
55};
56
57/**
58 * A header, followed by UTF8-encoded, 0-terminated string
59 */
60struct GNUNET_W32_CONSOLE_chars
61{
62 /**
63 * Type: GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_CHARS
64 */
65 struct GNUNET_MessageHeader header;
66
67 /* followed by a string */
68};
69
70GNUNET_NETWORK_STRUCT_END
71
72#endif