diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-01-02 09:26:10 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-01-02 09:26:10 +0000 |
commit | 1ac29e62ba9db3cac4d382a6ab629d6249cf58ad (patch) | |
tree | 5d66ae45dc4f62128625a1a365dc079f524d170c | |
parent | f1f198df545fbb423a61dc2fa945fe97bdcfe098 (diff) | |
download | gnunet-1ac29e62ba9db3cac4d382a6ab629d6249cf58ad.tar.gz gnunet-1ac29e62ba9db3cac4d382a6ab629d6249cf58ad.zip |
adding new GNUNET_HELPER_ API for communication with (SUID) helper binaries via stdin/stdout using standard GNUNET messages
-rw-r--r-- | src/include/Makefile.am | 1 | ||||
-rw-r--r-- | src/include/gnunet_helper_lib.h | 96 | ||||
-rw-r--r-- | src/util/Makefile.am | 1 | ||||
-rw-r--r-- | src/util/helper.c | 484 |
4 files changed, 582 insertions, 0 deletions
diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 417e200c2..b44efbf34 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am | |||
@@ -46,6 +46,7 @@ gnunetinclude_HEADERS = \ | |||
46 | gnunet_fs_service.h \ | 46 | gnunet_fs_service.h \ |
47 | gnunet_getopt_lib.h \ | 47 | gnunet_getopt_lib.h \ |
48 | gnunet_hello_lib.h \ | 48 | gnunet_hello_lib.h \ |
49 | gnunet_helper_lib.h \ | ||
49 | gnunet_load_lib.h \ | 50 | gnunet_load_lib.h \ |
50 | gnunet_mesh_service.h \ | 51 | gnunet_mesh_service.h \ |
51 | gnunet_nat_lib.h \ | 52 | gnunet_nat_lib.h \ |
diff --git a/src/include/gnunet_helper_lib.h b/src/include/gnunet_helper_lib.h new file mode 100644 index 000000000..7115748fc --- /dev/null +++ b/src/include/gnunet_helper_lib.h | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2011, 2012 Christian Grothoff | ||
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 include/gnunet_helper_lib.h | ||
23 | * @brief API for dealing with (SUID) helper processes that communicate via GNUNET_MessageHeaders on stdin/stdout | ||
24 | * @author Philipp Toelke | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #ifndef GNUNET_HELPER_LIB_H | ||
28 | #define GNUNET_HELPER_LIB_H | ||
29 | |||
30 | #include "gnunet_scheduler_lib.h" | ||
31 | #include "gnunet_server_lib.h" | ||
32 | |||
33 | /** | ||
34 | * The handle to a helper process. | ||
35 | */ | ||
36 | struct GNUNET_HELPER_Handle; | ||
37 | |||
38 | |||
39 | /** | ||
40 | * @brief Starts a helper and begins reading from it | ||
41 | * | ||
42 | * @param binary_name name of the binary to run | ||
43 | * @param binary_argv NULL-terminated list of arguments to give when starting the binary (this | ||
44 | * argument must not be modified by the client for | ||
45 | * the lifetime of the helper handle) | ||
46 | * @param cb function to call if we get messages from the helper | ||
47 | * @param cb_cls Closure for the callback | ||
48 | * @return the new Handle, NULL on error | ||
49 | */ | ||
50 | struct GNUNET_HELPER_Handle * | ||
51 | GNUNET_HELPER_start (const char *binary_name, | ||
52 | char *const binary_argv[], | ||
53 | GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls); | ||
54 | |||
55 | |||
56 | /** | ||
57 | * @brief Kills the helper, closes the pipe and frees the handle | ||
58 | * | ||
59 | * @param h handle to helper to stop | ||
60 | */ | ||
61 | void | ||
62 | GNUNET_HELPER_stop (struct GNUNET_HELPER_Handle *h); | ||
63 | |||
64 | |||
65 | /** | ||
66 | * Continuation function. | ||
67 | * | ||
68 | * @param cls closure | ||
69 | * @param result GNUNET_OK on success, | ||
70 | * GNUNET_NO if helper process died | ||
71 | * GNUNET_SYSERR during GNUNET_HELPER_stop | ||
72 | */ | ||
73 | typedef void (*GNUNET_HELPER_Continuation)(void *cls, | ||
74 | int result); | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Send an message to the helper. | ||
79 | * | ||
80 | * @param h helper to send message to | ||
81 | * @param msg message to send | ||
82 | * @param can_drop can the message be dropped if there is already one in the queue? | ||
83 | * @param cont continuation to run once the message is out | ||
84 | * @param cont_cls closure for 'cont' | ||
85 | * @return GNUNET_YES if the message will be sent | ||
86 | * GNUNET_NO if the message was dropped | ||
87 | */ | ||
88 | int | ||
89 | GNUNET_HELPER_send (struct GNUNET_HELPER_Handle *h, | ||
90 | const struct GNUNET_MessageHeader *msg, | ||
91 | int can_drop, | ||
92 | GNUNET_HELPER_Continuation cont, | ||
93 | void *cont_cls); | ||
94 | |||
95 | |||
96 | #endif /* end of include guard: GNUNET_HELPER_LIB_H */ | ||
diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 4ee0fe213..ec3884dc8 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am | |||
@@ -76,6 +76,7 @@ libgnunetutil_la_SOURCES = \ | |||
76 | disk.h \ | 76 | disk.h \ |
77 | getopt.c \ | 77 | getopt.c \ |
78 | getopt_helpers.c \ | 78 | getopt_helpers.c \ |
79 | helper.c \ | ||
79 | load.c \ | 80 | load.c \ |
80 | network.c \ | 81 | network.c \ |
81 | os_installation.c \ | 82 | os_installation.c \ |
diff --git a/src/util/helper.c b/src/util/helper.c new file mode 100644 index 000000000..c47b201c5 --- /dev/null +++ b/src/util/helper.c | |||
@@ -0,0 +1,484 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2011, 2012 Christian Grothoff | ||
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 util/helper.c | ||
23 | * @brief API for dealing with (SUID) helper processes that communicate via GNUNET_MessageHeaders on stdin/stdout | ||
24 | * @author Philipp Toelke | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * Entry in the queue of messages we need to transmit to the helper. | ||
33 | */ | ||
34 | struct HelperMessageQueueEntry | ||
35 | { | ||
36 | |||
37 | /** | ||
38 | * This is an entry in a DLL. | ||
39 | */ | ||
40 | struct HelperMessageQueueEntry *next; | ||
41 | |||
42 | /** | ||
43 | * This is an entry in a DLL. | ||
44 | */ | ||
45 | struct HelperMessageQueueEntry *prev; | ||
46 | |||
47 | /** | ||
48 | * Message to transmit (allocated at the end of this struct) | ||
49 | */ | ||
50 | const struct GNUNET_MessageHeader *msg; | ||
51 | |||
52 | /** | ||
53 | * Function to call upon completion. | ||
54 | */ | ||
55 | GNUNET_HELPER_Continuation cont; | ||
56 | |||
57 | /** | ||
58 | * Closure to 'cont'. | ||
59 | */ | ||
60 | void *cont_cls; | ||
61 | |||
62 | /** | ||
63 | * Current write position. | ||
64 | */ | ||
65 | unsigned int wpos; | ||
66 | |||
67 | }; | ||
68 | |||
69 | |||
70 | /** | ||
71 | * The handle to a helper process. | ||
72 | */ | ||
73 | struct GNUNET_HELPER_Handle | ||
74 | { | ||
75 | |||
76 | /** | ||
77 | * PipeHandle to receive data from the helper | ||
78 | */ | ||
79 | struct GNUNET_DISK_PipeHandle *helper_in; | ||
80 | |||
81 | /** | ||
82 | * PipeHandle to send data to the helper | ||
83 | */ | ||
84 | struct GNUNET_DISK_PipeHandle *helper_out; | ||
85 | |||
86 | /** | ||
87 | * FileHandle to receive data from the helper | ||
88 | */ | ||
89 | const struct GNUNET_DISK_FileHandle *fh_from_helper; | ||
90 | |||
91 | /** | ||
92 | * FileHandle to send data to the helper | ||
93 | */ | ||
94 | const struct GNUNET_DISK_FileHandle *fh_to_helper; | ||
95 | |||
96 | /** | ||
97 | * The process id of the helper | ||
98 | */ | ||
99 | struct GNUNET_OS_Process *helper_proc; | ||
100 | |||
101 | /** | ||
102 | * The Message-Tokenizer that tokenizes the messages comming from the helper | ||
103 | */ | ||
104 | struct GNUNET_SERVER_MessageStreamTokenizer *mst; | ||
105 | |||
106 | /** | ||
107 | * First message queued for transmission to helper. | ||
108 | */ | ||
109 | struct HelperMessageQueueEntry *mq_head; | ||
110 | |||
111 | /** | ||
112 | * Last message queued for transmission to helper. | ||
113 | */ | ||
114 | struct HelperMessageQueueEntry *mq_tail; | ||
115 | |||
116 | /** | ||
117 | * Binary to run. | ||
118 | */ | ||
119 | const char *binary_name; | ||
120 | |||
121 | /** | ||
122 | * NULL-terminated list of command-line arguments. | ||
123 | */ | ||
124 | char *const *binary_argv; | ||
125 | |||
126 | /** | ||
127 | * Task to read from the helper. | ||
128 | */ | ||
129 | GNUNET_SCHEDULER_TaskIdentifier read_task; | ||
130 | |||
131 | /** | ||
132 | * Task to read from the helper. | ||
133 | */ | ||
134 | GNUNET_SCHEDULER_TaskIdentifier write_task; | ||
135 | |||
136 | /** | ||
137 | * Restart task. | ||
138 | */ | ||
139 | GNUNET_SCHEDULER_TaskIdentifier restart_task; | ||
140 | }; | ||
141 | |||
142 | |||
143 | /** | ||
144 | * Stop the helper process, we're closing down or had an error. | ||
145 | * | ||
146 | * @param h handle to the helper process | ||
147 | */ | ||
148 | static void | ||
149 | stop_helper (struct GNUNET_HELPER_Handle *h) | ||
150 | { | ||
151 | struct HelperMessageQueueEntry *qe; | ||
152 | |||
153 | if (NULL != h->helper_proc) | ||
154 | { | ||
155 | GNUNET_OS_process_kill (h->helper_proc, SIGKILL); | ||
156 | GNUNET_OS_process_wait (h->helper_proc); | ||
157 | GNUNET_OS_process_close (h->helper_proc); | ||
158 | h->helper_proc = NULL; | ||
159 | } | ||
160 | if (GNUNET_SCHEDULER_NO_TASK != h->restart_task) | ||
161 | { | ||
162 | GNUNET_SCHEDULER_cancel (h->restart_task); | ||
163 | h->restart_task = GNUNET_SCHEDULER_NO_TASK; | ||
164 | } | ||
165 | if (GNUNET_SCHEDULER_NO_TASK != h->read_task) | ||
166 | { | ||
167 | GNUNET_SCHEDULER_cancel (h->read_task); | ||
168 | h->read_task = GNUNET_SCHEDULER_NO_TASK; | ||
169 | } | ||
170 | if (GNUNET_SCHEDULER_NO_TASK != h->write_task) | ||
171 | { | ||
172 | GNUNET_SCHEDULER_cancel (h->write_task); | ||
173 | h->write_task = GNUNET_SCHEDULER_NO_TASK; | ||
174 | } | ||
175 | if (NULL != h->helper_in) | ||
176 | { | ||
177 | GNUNET_DISK_pipe_close (h->helper_in); | ||
178 | h->helper_in = NULL; | ||
179 | h->fh_to_helper = NULL; | ||
180 | } | ||
181 | if (NULL != h->helper_out) | ||
182 | { | ||
183 | GNUNET_DISK_pipe_close (h->helper_out); | ||
184 | h->helper_out = NULL; | ||
185 | h->fh_from_helper = NULL; | ||
186 | } | ||
187 | while (NULL != (qe = h->mq_head)) | ||
188 | { | ||
189 | GNUNET_CONTAINER_DLL_remove (h->mq_head, | ||
190 | h->mq_tail, | ||
191 | qe); | ||
192 | qe->cont (qe->cont_cls, GNUNET_NO); | ||
193 | GNUNET_free (qe); | ||
194 | } | ||
195 | /* purge MST buffer */ | ||
196 | GNUNET_SERVER_mst_receive (h->mst, NULL, NULL, 0, GNUNET_YES, GNUNET_NO); | ||
197 | } | ||
198 | |||
199 | |||
200 | /** | ||
201 | * Restart the helper process. | ||
202 | * | ||
203 | * @param cls handle to the helper process | ||
204 | * @param tc scheduler context | ||
205 | */ | ||
206 | static void | ||
207 | restart_task (void *cls, | ||
208 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
209 | |||
210 | |||
211 | /** | ||
212 | * Read from the helper-process | ||
213 | * | ||
214 | * @param cls handle to the helper process | ||
215 | * @param tc scheduler context | ||
216 | */ | ||
217 | static void | ||
218 | helper_read (void *cls, | ||
219 | const struct GNUNET_SCHEDULER_TaskContext *tsdkctx) | ||
220 | { | ||
221 | struct GNUNET_HELPER_Handle*h = cls; | ||
222 | char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE]; | ||
223 | ssize_t t; | ||
224 | |||
225 | h->read_task = GNUNET_SCHEDULER_NO_TASK; | ||
226 | if (0 != (tsdkctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
227 | { | ||
228 | /* try again */ | ||
229 | h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
230 | h->fh_from_helper, &helper_read, h); | ||
231 | return; | ||
232 | } | ||
233 | t = GNUNET_DISK_file_read (h->fh_from_helper, &buf, sizeof (buf)); | ||
234 | if (t <= 0) | ||
235 | { | ||
236 | /* On read-error, restart the helper */ | ||
237 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
238 | _("Error reading from `%s': %s\n"), | ||
239 | h->binary_name, | ||
240 | STRERROR (errno)); | ||
241 | stop_helper (h); | ||
242 | /* Restart the helper */ | ||
243 | h->restart_task = | ||
244 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
245 | &restart_task, h); | ||
246 | return; | ||
247 | } | ||
248 | if (GNUNET_SYSERR == | ||
249 | GNUNET_SERVER_mst_receive (h->mst, NULL, buf, t, GNUNET_NO, GNUNET_NO)) | ||
250 | { | ||
251 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
252 | _("Failed to parse inbound message from helper `%s'\n"), | ||
253 | h->binary_name); | ||
254 | stop_helper (h); | ||
255 | /* Restart the helper */ | ||
256 | h->restart_task = | ||
257 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
258 | &restart_task, h); | ||
259 | return; | ||
260 | |||
261 | } | ||
262 | h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
263 | h->fh_from_helper, &helper_read, h); | ||
264 | } | ||
265 | |||
266 | |||
267 | /** | ||
268 | * Start the helper process. | ||
269 | * | ||
270 | * @param h handle to the helper process | ||
271 | */ | ||
272 | static void | ||
273 | start_helper (struct GNUNET_HELPER_Handle *h) | ||
274 | { | ||
275 | h->helper_in = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO); | ||
276 | h->helper_out = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES); | ||
277 | if ( (h->helper_in == NULL) || (h->helper_out == NULL)) | ||
278 | { | ||
279 | /* out of file descriptors? try again later... */ | ||
280 | stop_helper (h); | ||
281 | h->restart_task = | ||
282 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
283 | &restart_task, h); | ||
284 | return; | ||
285 | } | ||
286 | h->fh_from_helper = | ||
287 | GNUNET_DISK_pipe_handle (h->helper_out, GNUNET_DISK_PIPE_END_READ); | ||
288 | GNUNET_DISK_pipe_close_end (h->helper_out, GNUNET_DISK_PIPE_END_WRITE); | ||
289 | h->fh_to_helper = | ||
290 | GNUNET_DISK_pipe_handle (h->helper_in, GNUNET_DISK_PIPE_END_WRITE); | ||
291 | GNUNET_DISK_pipe_close_end (h->helper_in, GNUNET_DISK_PIPE_END_READ); | ||
292 | h->helper_proc = | ||
293 | GNUNET_OS_start_process_vap (h->helper_in, h->helper_out, | ||
294 | h->binary_name, | ||
295 | h->binary_argv); | ||
296 | if (NULL == h->helper_proc) | ||
297 | { | ||
298 | /* failed to start process? try again later... */ | ||
299 | stop_helper (h); | ||
300 | h->restart_task = | ||
301 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
302 | &restart_task, h); | ||
303 | return; | ||
304 | } | ||
305 | h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
306 | h->fh_from_helper, | ||
307 | &helper_read, | ||
308 | h); | ||
309 | } | ||
310 | |||
311 | |||
312 | /** | ||
313 | * Restart the helper process. | ||
314 | * | ||
315 | * @param cls handle to the helper process | ||
316 | * @param tc scheduler context | ||
317 | */ | ||
318 | static void | ||
319 | restart_task (void *cls, | ||
320 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
321 | { | ||
322 | struct GNUNET_HELPER_Handle*h = cls; | ||
323 | |||
324 | h->restart_task = GNUNET_SCHEDULER_NO_TASK; | ||
325 | start_helper (h); | ||
326 | } | ||
327 | |||
328 | |||
329 | /** | ||
330 | * @brief Starts a helper and begins reading from it | ||
331 | * | ||
332 | * @param binary_name name of the binary to run | ||
333 | * @param binary_argv NULL-terminated list of arguments to give when starting the binary (this | ||
334 | * argument must not be modified by the client for | ||
335 | * the lifetime of the helper h) | ||
336 | * @param cb function to call if we get messages from the helper | ||
337 | * @param cb_cls Closure for the callback | ||
338 | * @return the new H, NULL on error | ||
339 | */ | ||
340 | struct GNUNET_HELPER_Handle* | ||
341 | GNUNET_HELPER_start (const char *binary_name, | ||
342 | char *const binary_argv[], | ||
343 | GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls) | ||
344 | { | ||
345 | struct GNUNET_HELPER_Handle*h; | ||
346 | |||
347 | h = GNUNET_malloc (sizeof (struct GNUNET_HELPER_Handle)); | ||
348 | h->binary_name = binary_name; | ||
349 | h->binary_argv = binary_argv; | ||
350 | h->mst = GNUNET_SERVER_mst_create (cb, cb_cls); | ||
351 | start_helper (h); | ||
352 | return h; | ||
353 | } | ||
354 | |||
355 | |||
356 | /** | ||
357 | * @brief Kills the helper, closes the pipe and frees the h | ||
358 | * | ||
359 | * @param h h to helper to stop | ||
360 | */ | ||
361 | void | ||
362 | GNUNET_HELPER_stop (struct GNUNET_HELPER_Handle *h) | ||
363 | { | ||
364 | struct HelperMessageQueueEntry *qe; | ||
365 | |||
366 | /* signal pending writes that we were stopped */ | ||
367 | while (NULL != (qe = h->mq_head)) | ||
368 | { | ||
369 | GNUNET_CONTAINER_DLL_remove (h->mq_head, | ||
370 | h->mq_tail, | ||
371 | qe); | ||
372 | qe->cont (qe->cont_cls, GNUNET_SYSERR); | ||
373 | GNUNET_free (qe); | ||
374 | } | ||
375 | stop_helper (h); | ||
376 | GNUNET_SERVER_mst_destroy (h->mst); | ||
377 | GNUNET_free (h); | ||
378 | } | ||
379 | |||
380 | |||
381 | /** | ||
382 | * Write to the helper-process | ||
383 | * | ||
384 | * @param cls handle to the helper process | ||
385 | * @param tc scheduler context | ||
386 | */ | ||
387 | static void | ||
388 | helper_write (void *cls, | ||
389 | const struct GNUNET_SCHEDULER_TaskContext *tsdkctx) | ||
390 | { | ||
391 | struct GNUNET_HELPER_Handle *h = cls; | ||
392 | struct HelperMessageQueueEntry *qe; | ||
393 | const char *buf; | ||
394 | ssize_t t; | ||
395 | |||
396 | h->write_task = GNUNET_SCHEDULER_NO_TASK; | ||
397 | if (0 != (tsdkctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
398 | { | ||
399 | /* try again */ | ||
400 | h->write_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
401 | h->fh_to_helper, &helper_write, h); | ||
402 | return; | ||
403 | } | ||
404 | if (NULL == (qe = h->mq_head)) | ||
405 | return; /* how did this happen? */ | ||
406 | buf = (const char*) qe->msg; | ||
407 | t = GNUNET_DISK_file_write (h->fh_to_helper, &buf[qe->wpos], ntohs (qe->msg->size) - qe->wpos); | ||
408 | if (t <= 0) | ||
409 | { | ||
410 | /* On write-error, restart the helper */ | ||
411 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
412 | _("Error writing to `%s': %s\n"), | ||
413 | h->binary_name, | ||
414 | STRERROR (errno)); | ||
415 | stop_helper (h); | ||
416 | /* Restart the helper */ | ||
417 | h->restart_task = | ||
418 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
419 | &restart_task, h); | ||
420 | return; | ||
421 | } | ||
422 | qe->wpos += t; | ||
423 | if (qe->wpos == ntohs (qe->msg->size)) | ||
424 | { | ||
425 | GNUNET_CONTAINER_DLL_remove (h->mq_head, | ||
426 | h->mq_tail, | ||
427 | qe); | ||
428 | if (NULL != qe->cont) | ||
429 | qe->cont (qe->cont_cls, GNUNET_YES); | ||
430 | GNUNET_free (qe); | ||
431 | } | ||
432 | if (NULL != h->mq_head) | ||
433 | h->write_task = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
434 | h->fh_to_helper, | ||
435 | &helper_write, | ||
436 | h); | ||
437 | } | ||
438 | |||
439 | |||
440 | /** | ||
441 | * Send an message to the helper. | ||
442 | * | ||
443 | * @param h helper to send message to | ||
444 | * @param msg message to send | ||
445 | * @param can_drop can the message be dropped if there is already one in the queue? | ||
446 | * @param cont continuation to run once the message is out (PREREQ_DONE on succees, CANCEL | ||
447 | * if the helper process died, NULL during GNUNET_HELPER_stop). | ||
448 | * @param cont_cls closure for 'cont' | ||
449 | * @return GNUNET_YES if the message will be sent | ||
450 | * GNUNET_NO if the message was dropped | ||
451 | */ | ||
452 | int | ||
453 | GNUNET_HELPER_send (struct GNUNET_HELPER_Handle *h, | ||
454 | const struct GNUNET_MessageHeader *msg, | ||
455 | int can_drop, | ||
456 | GNUNET_HELPER_Continuation cont, | ||
457 | void *cont_cls) | ||
458 | { | ||
459 | struct HelperMessageQueueEntry *qe; | ||
460 | uint16_t mlen; | ||
461 | |||
462 | if ( (GNUNET_YES == can_drop) && | ||
463 | (h->mq_head != NULL) ) | ||
464 | return GNUNET_NO; | ||
465 | mlen = ntohs (msg->size); | ||
466 | qe = GNUNET_malloc (sizeof (struct HelperMessageQueueEntry) + mlen); | ||
467 | qe->msg = (const struct GNUNET_MessageHeader*) &qe[1]; | ||
468 | memcpy (&qe[1], msg, mlen); | ||
469 | qe->cont = cont; | ||
470 | qe->cont_cls = cont_cls; | ||
471 | GNUNET_CONTAINER_DLL_insert_tail (h->mq_head, | ||
472 | h->mq_tail, | ||
473 | qe); | ||
474 | if (GNUNET_SCHEDULER_NO_TASK == h->write_task) | ||
475 | h->write_task = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
476 | h->fh_to_helper, | ||
477 | &helper_write, | ||
478 | h); | ||
479 | |||
480 | return GNUNET_YES; | ||
481 | } | ||
482 | |||
483 | |||
484 | /* end of helper.c */ | ||