diff options
Diffstat (limited to 'src/util/helper.c')
-rw-r--r-- | src/util/helper.c | 673 |
1 files changed, 0 insertions, 673 deletions
diff --git a/src/util/helper.c b/src/util/helper.c deleted file mode 100644 index fe8643d31..000000000 --- a/src/util/helper.c +++ /dev/null | |||
@@ -1,673 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011, 2012 Christian Grothoff | ||
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 | |||
21 | /** | ||
22 | * @file util/helper.c | ||
23 | * @brief API for dealing with (SUID) helper processes that communicate via | ||
24 | * GNUNET_MessageHeaders on stdin/stdout | ||
25 | * @author Philipp Toelke | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | |||
32 | /** | ||
33 | * Entry in the queue of messages we need to transmit to the helper. | ||
34 | */ | ||
35 | struct GNUNET_HELPER_SendHandle | ||
36 | { | ||
37 | /** | ||
38 | * This is an entry in a DLL. | ||
39 | */ | ||
40 | struct GNUNET_HELPER_SendHandle *next; | ||
41 | |||
42 | /** | ||
43 | * This is an entry in a DLL. | ||
44 | */ | ||
45 | struct GNUNET_HELPER_SendHandle *prev; | ||
46 | |||
47 | /** | ||
48 | * Message to transmit (allocated at the end of this struct) | ||
49 | */ | ||
50 | const struct GNUNET_MessageHeader *msg; | ||
51 | |||
52 | /** | ||
53 | * The handle to a helper process. | ||
54 | */ | ||
55 | struct GNUNET_HELPER_Handle *h; | ||
56 | |||
57 | /** | ||
58 | * Function to call upon completion. | ||
59 | */ | ||
60 | GNUNET_HELPER_Continuation cont; | ||
61 | |||
62 | /** | ||
63 | * Closure to 'cont'. | ||
64 | */ | ||
65 | void *cont_cls; | ||
66 | |||
67 | /** | ||
68 | * Current write position. | ||
69 | */ | ||
70 | unsigned int wpos; | ||
71 | }; | ||
72 | |||
73 | |||
74 | /** | ||
75 | * The handle to a helper process. | ||
76 | */ | ||
77 | struct GNUNET_HELPER_Handle | ||
78 | { | ||
79 | /** | ||
80 | * PipeHandle to receive data from the helper | ||
81 | */ | ||
82 | struct GNUNET_DISK_PipeHandle *helper_in; | ||
83 | |||
84 | /** | ||
85 | * PipeHandle to send data to the helper | ||
86 | */ | ||
87 | struct GNUNET_DISK_PipeHandle *helper_out; | ||
88 | |||
89 | /** | ||
90 | * FileHandle to receive data from the helper | ||
91 | */ | ||
92 | const struct GNUNET_DISK_FileHandle *fh_from_helper; | ||
93 | |||
94 | /** | ||
95 | * FileHandle to send data to the helper | ||
96 | */ | ||
97 | const struct GNUNET_DISK_FileHandle *fh_to_helper; | ||
98 | |||
99 | /** | ||
100 | * The process id of the helper | ||
101 | */ | ||
102 | struct GNUNET_OS_Process *helper_proc; | ||
103 | |||
104 | /** | ||
105 | * The Message-Tokenizer that tokenizes the messages coming from the helper | ||
106 | */ | ||
107 | struct GNUNET_MessageStreamTokenizer *mst; | ||
108 | |||
109 | /** | ||
110 | * The exception callback | ||
111 | */ | ||
112 | GNUNET_HELPER_ExceptionCallback exp_cb; | ||
113 | |||
114 | /** | ||
115 | * The closure for callbacks | ||
116 | */ | ||
117 | void *cb_cls; | ||
118 | |||
119 | /** | ||
120 | * First message queued for transmission to helper. | ||
121 | */ | ||
122 | struct GNUNET_HELPER_SendHandle *sh_head; | ||
123 | |||
124 | /** | ||
125 | * Last message queued for transmission to helper. | ||
126 | */ | ||
127 | struct GNUNET_HELPER_SendHandle *sh_tail; | ||
128 | |||
129 | /** | ||
130 | * Binary to run. | ||
131 | */ | ||
132 | char *binary_name; | ||
133 | |||
134 | /** | ||
135 | * NULL-terminated list of command-line arguments. | ||
136 | */ | ||
137 | char **binary_argv; | ||
138 | |||
139 | /** | ||
140 | * Task to read from the helper. | ||
141 | */ | ||
142 | struct GNUNET_SCHEDULER_Task *read_task; | ||
143 | |||
144 | /** | ||
145 | * Task to read from the helper. | ||
146 | */ | ||
147 | struct GNUNET_SCHEDULER_Task *write_task; | ||
148 | |||
149 | /** | ||
150 | * Restart task. | ||
151 | */ | ||
152 | struct GNUNET_SCHEDULER_Task *restart_task; | ||
153 | |||
154 | /** | ||
155 | * Does the helper support the use of a control pipe for signalling? | ||
156 | */ | ||
157 | int with_control_pipe; | ||
158 | |||
159 | /** | ||
160 | * Count start attempts to increase linear back off | ||
161 | */ | ||
162 | unsigned int retry_back_off; | ||
163 | }; | ||
164 | |||
165 | |||
166 | int | ||
167 | GNUNET_HELPER_kill (struct GNUNET_HELPER_Handle *h, int soft_kill) | ||
168 | { | ||
169 | struct GNUNET_HELPER_SendHandle *sh; | ||
170 | int ret; | ||
171 | |||
172 | while (NULL != (sh = h->sh_head)) | ||
173 | { | ||
174 | GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh); | ||
175 | if (NULL != sh->cont) | ||
176 | sh->cont (sh->cont_cls, GNUNET_NO); | ||
177 | GNUNET_free (sh); | ||
178 | } | ||
179 | if (NULL != h->restart_task) | ||
180 | { | ||
181 | GNUNET_SCHEDULER_cancel (h->restart_task); | ||
182 | h->restart_task = NULL; | ||
183 | } | ||
184 | if (NULL != h->read_task) | ||
185 | { | ||
186 | GNUNET_SCHEDULER_cancel (h->read_task); | ||
187 | h->read_task = NULL; | ||
188 | } | ||
189 | if (NULL == h->helper_proc) | ||
190 | return GNUNET_SYSERR; | ||
191 | if (GNUNET_YES == soft_kill) | ||
192 | { | ||
193 | /* soft-kill only possible with pipes */ | ||
194 | GNUNET_assert (NULL != h->helper_in); | ||
195 | ret = GNUNET_DISK_pipe_close (h->helper_in); | ||
196 | h->helper_in = NULL; | ||
197 | h->fh_to_helper = NULL; | ||
198 | return ret; | ||
199 | } | ||
200 | if (0 != GNUNET_OS_process_kill (h->helper_proc, GNUNET_TERM_SIG)) | ||
201 | return GNUNET_SYSERR; | ||
202 | return GNUNET_OK; | ||
203 | } | ||
204 | |||
205 | |||
206 | int | ||
207 | GNUNET_HELPER_wait (struct GNUNET_HELPER_Handle *h) | ||
208 | { | ||
209 | struct GNUNET_HELPER_SendHandle *sh; | ||
210 | int ret; | ||
211 | |||
212 | ret = GNUNET_SYSERR; | ||
213 | if (NULL != h->helper_proc) | ||
214 | { | ||
215 | ret = GNUNET_OS_process_wait (h->helper_proc); | ||
216 | GNUNET_OS_process_destroy (h->helper_proc); | ||
217 | h->helper_proc = NULL; | ||
218 | } | ||
219 | if (NULL != h->read_task) | ||
220 | { | ||
221 | GNUNET_SCHEDULER_cancel (h->read_task); | ||
222 | h->read_task = NULL; | ||
223 | } | ||
224 | if (NULL != h->write_task) | ||
225 | { | ||
226 | GNUNET_SCHEDULER_cancel (h->write_task); | ||
227 | h->write_task = NULL; | ||
228 | } | ||
229 | if (NULL != h->helper_in) | ||
230 | { | ||
231 | GNUNET_DISK_pipe_close (h->helper_in); | ||
232 | h->helper_in = NULL; | ||
233 | h->fh_to_helper = NULL; | ||
234 | } | ||
235 | if (NULL != h->helper_out) | ||
236 | { | ||
237 | GNUNET_DISK_pipe_close (h->helper_out); | ||
238 | h->helper_out = NULL; | ||
239 | h->fh_from_helper = NULL; | ||
240 | } | ||
241 | while (NULL != (sh = h->sh_head)) | ||
242 | { | ||
243 | GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh); | ||
244 | if (NULL != sh->cont) | ||
245 | sh->cont (sh->cont_cls, GNUNET_NO); | ||
246 | GNUNET_free (sh); | ||
247 | } | ||
248 | /* purge MST buffer */ | ||
249 | if (NULL != h->mst) | ||
250 | (void) GNUNET_MST_from_buffer (h->mst, NULL, 0, GNUNET_YES, GNUNET_NO); | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | |||
255 | /** | ||
256 | * Stop the helper process, we're closing down or had an error. | ||
257 | * | ||
258 | * @param h handle to the helper process | ||
259 | * @param soft_kill if #GNUNET_YES, signals termination by closing the helper's | ||
260 | * stdin; #GNUNET_NO to signal termination by sending SIGTERM to helper | ||
261 | */ | ||
262 | static void | ||
263 | stop_helper (struct GNUNET_HELPER_Handle *h, int soft_kill) | ||
264 | { | ||
265 | if (NULL != h->restart_task) | ||
266 | { | ||
267 | GNUNET_SCHEDULER_cancel (h->restart_task); | ||
268 | h->restart_task = NULL; | ||
269 | } | ||
270 | else | ||
271 | { | ||
272 | GNUNET_break (GNUNET_OK == GNUNET_HELPER_kill (h, soft_kill)); | ||
273 | GNUNET_break (GNUNET_OK == GNUNET_HELPER_wait (h)); | ||
274 | } | ||
275 | } | ||
276 | |||
277 | |||
278 | /** | ||
279 | * Restart the helper process. | ||
280 | * | ||
281 | * @param cls handle to the helper process | ||
282 | */ | ||
283 | static void | ||
284 | restart_task (void *cls); | ||
285 | |||
286 | |||
287 | /** | ||
288 | * Read from the helper-process | ||
289 | * | ||
290 | * @param cls handle to the helper process | ||
291 | */ | ||
292 | static void | ||
293 | helper_read (void *cls) | ||
294 | { | ||
295 | struct GNUNET_HELPER_Handle *h = cls; | ||
296 | char buf[GNUNET_MAX_MESSAGE_SIZE] GNUNET_ALIGN; | ||
297 | ssize_t t; | ||
298 | |||
299 | h->read_task = NULL; | ||
300 | t = GNUNET_DISK_file_read (h->fh_from_helper, &buf, sizeof(buf)); | ||
301 | if (t < 0) | ||
302 | { | ||
303 | /* On read-error, restart the helper */ | ||
304 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
305 | _ ("Error reading from `%s': %s\n"), | ||
306 | h->binary_name, | ||
307 | strerror (errno)); | ||
308 | if (NULL != h->exp_cb) | ||
309 | { | ||
310 | h->exp_cb (h->cb_cls); | ||
311 | GNUNET_HELPER_stop (h, GNUNET_NO); | ||
312 | return; | ||
313 | } | ||
314 | stop_helper (h, GNUNET_NO); | ||
315 | /* Restart the helper */ | ||
316 | h->restart_task = GNUNET_SCHEDULER_add_delayed ( | ||
317 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
318 | h->retry_back_off), | ||
319 | &restart_task, | ||
320 | h); | ||
321 | return; | ||
322 | } | ||
323 | if (0 == t) | ||
324 | { | ||
325 | /* this happens if the helper is shut down via a | ||
326 | signal, so it is not a "hard" error */ | ||
327 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
328 | "Got 0 bytes from helper `%s' (EOF)\n", | ||
329 | h->binary_name); | ||
330 | if (NULL != h->exp_cb) | ||
331 | { | ||
332 | h->exp_cb (h->cb_cls); | ||
333 | GNUNET_HELPER_stop (h, GNUNET_NO); | ||
334 | return; | ||
335 | } | ||
336 | stop_helper (h, GNUNET_NO); | ||
337 | /* Restart the helper */ | ||
338 | h->restart_task = GNUNET_SCHEDULER_add_delayed ( | ||
339 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
340 | h->retry_back_off), | ||
341 | &restart_task, | ||
342 | h); | ||
343 | return; | ||
344 | } | ||
345 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
346 | "Got %u bytes from helper `%s'\n", | ||
347 | (unsigned int) t, | ||
348 | h->binary_name); | ||
349 | h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
350 | h->fh_from_helper, | ||
351 | &helper_read, | ||
352 | h); | ||
353 | if (GNUNET_SYSERR == | ||
354 | GNUNET_MST_from_buffer (h->mst, buf, t, GNUNET_NO, GNUNET_NO)) | ||
355 | { | ||
356 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
357 | _ ("Failed to parse inbound message from helper `%s'\n"), | ||
358 | h->binary_name); | ||
359 | if (NULL != h->exp_cb) | ||
360 | { | ||
361 | h->exp_cb (h->cb_cls); | ||
362 | GNUNET_HELPER_stop (h, GNUNET_NO); | ||
363 | return; | ||
364 | } | ||
365 | stop_helper (h, GNUNET_NO); | ||
366 | /* Restart the helper */ | ||
367 | h->restart_task = GNUNET_SCHEDULER_add_delayed ( | ||
368 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
369 | h->retry_back_off), | ||
370 | &restart_task, | ||
371 | h); | ||
372 | return; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | |||
377 | /** | ||
378 | * Start the helper process. | ||
379 | * | ||
380 | * @param h handle to the helper process | ||
381 | */ | ||
382 | static void | ||
383 | start_helper (struct GNUNET_HELPER_Handle *h) | ||
384 | { | ||
385 | h->helper_in = | ||
386 | GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW); | ||
387 | h->helper_out = | ||
388 | GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW); | ||
389 | if ((h->helper_in == NULL) || (h->helper_out == NULL)) | ||
390 | { | ||
391 | /* out of file descriptors? try again later... */ | ||
392 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
393 | "out of file descriptors? try again later\n"); | ||
394 | stop_helper (h, GNUNET_NO); | ||
395 | h->restart_task = GNUNET_SCHEDULER_add_delayed ( | ||
396 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
397 | h->retry_back_off), | ||
398 | &restart_task, | ||
399 | h); | ||
400 | return; | ||
401 | } | ||
402 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
403 | "Starting HELPER process `%s'\n", | ||
404 | h->binary_name); | ||
405 | h->fh_from_helper = | ||
406 | GNUNET_DISK_pipe_handle (h->helper_out, GNUNET_DISK_PIPE_END_READ); | ||
407 | h->fh_to_helper = | ||
408 | GNUNET_DISK_pipe_handle (h->helper_in, GNUNET_DISK_PIPE_END_WRITE); | ||
409 | h->helper_proc = GNUNET_OS_start_process_vap (h->with_control_pipe | ||
410 | ? GNUNET_OS_INHERIT_STD_ERR | ||
411 | | GNUNET_OS_USE_PIPE_CONTROL | ||
412 | : GNUNET_OS_INHERIT_STD_ERR, | ||
413 | h->helper_in, | ||
414 | h->helper_out, | ||
415 | NULL, | ||
416 | h->binary_name, | ||
417 | h->binary_argv); | ||
418 | if (NULL == h->helper_proc) | ||
419 | { | ||
420 | /* failed to start process? try again later... */ | ||
421 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
422 | "failed to start process? try again later\n"); | ||
423 | stop_helper (h, GNUNET_NO); | ||
424 | h->restart_task = GNUNET_SCHEDULER_add_delayed ( | ||
425 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
426 | h->retry_back_off), | ||
427 | &restart_task, | ||
428 | h); | ||
429 | return; | ||
430 | } | ||
431 | GNUNET_DISK_pipe_close_end (h->helper_out, GNUNET_DISK_PIPE_END_WRITE); | ||
432 | GNUNET_DISK_pipe_close_end (h->helper_in, GNUNET_DISK_PIPE_END_READ); | ||
433 | if (NULL != h->mst) | ||
434 | h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
435 | h->fh_from_helper, | ||
436 | &helper_read, | ||
437 | h); | ||
438 | } | ||
439 | |||
440 | |||
441 | /** | ||
442 | * Restart the helper process. | ||
443 | * | ||
444 | * @param cls handle to the helper process | ||
445 | */ | ||
446 | static void | ||
447 | restart_task (void *cls) | ||
448 | { | ||
449 | struct GNUNET_HELPER_Handle *h = cls; | ||
450 | |||
451 | h->restart_task = NULL; | ||
452 | h->retry_back_off++; | ||
453 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
454 | "Restarting helper with back-off %u\n", | ||
455 | h->retry_back_off); | ||
456 | start_helper (h); | ||
457 | } | ||
458 | |||
459 | |||
460 | struct GNUNET_HELPER_Handle * | ||
461 | GNUNET_HELPER_start (int with_control_pipe, | ||
462 | const char *binary_name, | ||
463 | char *const binary_argv[], | ||
464 | GNUNET_MessageTokenizerCallback cb, | ||
465 | GNUNET_HELPER_ExceptionCallback exp_cb, | ||
466 | void *cb_cls) | ||
467 | { | ||
468 | struct GNUNET_HELPER_Handle *h; | ||
469 | unsigned int c; | ||
470 | |||
471 | h = GNUNET_new (struct GNUNET_HELPER_Handle); | ||
472 | h->with_control_pipe = with_control_pipe; | ||
473 | /* Lookup in libexec path only if we are starting gnunet helpers */ | ||
474 | if (NULL != strstr (binary_name, "gnunet")) | ||
475 | h->binary_name = GNUNET_OS_get_libexec_binary_path (binary_name); | ||
476 | else | ||
477 | h->binary_name = GNUNET_strdup (binary_name); | ||
478 | for (c = 0; NULL != binary_argv[c]; c++) | ||
479 | ; | ||
480 | h->binary_argv = GNUNET_malloc (sizeof(char *) * (c + 1)); | ||
481 | for (c = 0; NULL != binary_argv[c]; c++) | ||
482 | h->binary_argv[c] = GNUNET_strdup (binary_argv[c]); | ||
483 | h->binary_argv[c] = NULL; | ||
484 | h->cb_cls = cb_cls; | ||
485 | if (NULL != cb) | ||
486 | h->mst = GNUNET_MST_create (cb, h->cb_cls); | ||
487 | h->exp_cb = exp_cb; | ||
488 | h->retry_back_off = 0; | ||
489 | start_helper (h); | ||
490 | return h; | ||
491 | } | ||
492 | |||
493 | |||
494 | /** | ||
495 | * Free's the resources occupied by the helper handle | ||
496 | * | ||
497 | * @param h the helper handle to free | ||
498 | */ | ||
499 | void | ||
500 | GNUNET_HELPER_destroy (struct GNUNET_HELPER_Handle *h) | ||
501 | { | ||
502 | unsigned int c; | ||
503 | struct GNUNET_HELPER_SendHandle *sh; | ||
504 | |||
505 | if (NULL != h->write_task) | ||
506 | { | ||
507 | GNUNET_SCHEDULER_cancel (h->write_task); | ||
508 | h->write_task = NULL; | ||
509 | } | ||
510 | GNUNET_assert (NULL == h->read_task); | ||
511 | GNUNET_assert (NULL == h->restart_task); | ||
512 | while (NULL != (sh = h->sh_head)) | ||
513 | { | ||
514 | GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh); | ||
515 | if (NULL != sh->cont) | ||
516 | sh->cont (sh->cont_cls, GNUNET_SYSERR); | ||
517 | GNUNET_free (sh); | ||
518 | } | ||
519 | if (NULL != h->mst) | ||
520 | GNUNET_MST_destroy (h->mst); | ||
521 | GNUNET_free (h->binary_name); | ||
522 | for (c = 0; h->binary_argv[c] != NULL; c++) | ||
523 | GNUNET_free (h->binary_argv[c]); | ||
524 | GNUNET_free (h->binary_argv); | ||
525 | GNUNET_free (h); | ||
526 | } | ||
527 | |||
528 | |||
529 | /** | ||
530 | * Kills the helper, closes the pipe and frees the handle | ||
531 | * | ||
532 | * @param h handle to helper to stop | ||
533 | * @param soft_kill if #GNUNET_YES, signals termination by closing the helper's | ||
534 | * stdin; #GNUNET_NO to signal termination by sending SIGTERM to helper | ||
535 | */ | ||
536 | void | ||
537 | GNUNET_HELPER_stop (struct GNUNET_HELPER_Handle *h, int soft_kill) | ||
538 | { | ||
539 | h->exp_cb = NULL; | ||
540 | stop_helper (h, soft_kill); | ||
541 | GNUNET_HELPER_destroy (h); | ||
542 | } | ||
543 | |||
544 | |||
545 | /** | ||
546 | * Write to the helper-process | ||
547 | * | ||
548 | * @param cls handle to the helper process | ||
549 | */ | ||
550 | static void | ||
551 | helper_write (void *cls) | ||
552 | { | ||
553 | struct GNUNET_HELPER_Handle *h = cls; | ||
554 | struct GNUNET_HELPER_SendHandle *sh; | ||
555 | const char *buf; | ||
556 | ssize_t t; | ||
557 | |||
558 | h->write_task = NULL; | ||
559 | if (NULL == (sh = h->sh_head)) | ||
560 | { | ||
561 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Helper write had no work!\n"); | ||
562 | return; /* how did this happen? */ | ||
563 | } | ||
564 | buf = (const char *) sh->msg; | ||
565 | t = GNUNET_DISK_file_write (h->fh_to_helper, | ||
566 | &buf[sh->wpos], | ||
567 | ntohs (sh->msg->size) - sh->wpos); | ||
568 | if (-1 == t) | ||
569 | { | ||
570 | /* On write-error, restart the helper */ | ||
571 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
572 | _ ("Error writing to `%s': %s\n"), | ||
573 | h->binary_name, | ||
574 | strerror (errno)); | ||
575 | if (NULL != h->exp_cb) | ||
576 | { | ||
577 | h->exp_cb (h->cb_cls); | ||
578 | GNUNET_HELPER_stop (h, GNUNET_NO); | ||
579 | return; | ||
580 | } | ||
581 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
582 | "Stopping and restarting helper task!\n"); | ||
583 | stop_helper (h, GNUNET_NO); | ||
584 | /* Restart the helper */ | ||
585 | h->restart_task = GNUNET_SCHEDULER_add_delayed ( | ||
586 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
587 | h->retry_back_off), | ||
588 | &restart_task, | ||
589 | h); | ||
590 | return; | ||
591 | } | ||
592 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
593 | "Transmitted %u bytes to %s\n", | ||
594 | (unsigned int) t, | ||
595 | h->binary_name); | ||
596 | sh->wpos += t; | ||
597 | if (sh->wpos == ntohs (sh->msg->size)) | ||
598 | { | ||
599 | GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh); | ||
600 | if (NULL != sh->cont) | ||
601 | sh->cont (sh->cont_cls, GNUNET_YES); | ||
602 | GNUNET_free (sh); | ||
603 | } | ||
604 | if (NULL != h->sh_head) | ||
605 | h->write_task = | ||
606 | GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
607 | h->fh_to_helper, | ||
608 | &helper_write, | ||
609 | h); | ||
610 | } | ||
611 | |||
612 | |||
613 | struct GNUNET_HELPER_SendHandle * | ||
614 | GNUNET_HELPER_send (struct GNUNET_HELPER_Handle *h, | ||
615 | const struct GNUNET_MessageHeader *msg, | ||
616 | int can_drop, | ||
617 | GNUNET_HELPER_Continuation cont, | ||
618 | void *cont_cls) | ||
619 | { | ||
620 | struct GNUNET_HELPER_SendHandle *sh; | ||
621 | uint16_t mlen; | ||
622 | |||
623 | if (NULL == h->fh_to_helper) | ||
624 | return NULL; | ||
625 | if ((GNUNET_YES == can_drop) && (NULL != h->sh_head)) | ||
626 | return NULL; | ||
627 | mlen = ntohs (msg->size); | ||
628 | sh = GNUNET_malloc (sizeof(struct GNUNET_HELPER_SendHandle) + mlen); | ||
629 | sh->msg = (const struct GNUNET_MessageHeader *) &sh[1]; | ||
630 | GNUNET_memcpy (&sh[1], msg, mlen); | ||
631 | sh->h = h; | ||
632 | sh->cont = cont; | ||
633 | sh->cont_cls = cont_cls; | ||
634 | GNUNET_CONTAINER_DLL_insert_tail (h->sh_head, h->sh_tail, sh); | ||
635 | if (NULL == h->write_task) | ||
636 | h->write_task = | ||
637 | GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
638 | h->fh_to_helper, | ||
639 | &helper_write, | ||
640 | h); | ||
641 | |||
642 | return sh; | ||
643 | } | ||
644 | |||
645 | |||
646 | /** | ||
647 | * Cancel a #GNUNET_HELPER_send operation. If possible, transmitting the | ||
648 | * message is also aborted, but at least 'cont' won't be | ||
649 | * called. | ||
650 | * | ||
651 | * @param sh operation to cancel | ||
652 | */ | ||
653 | void | ||
654 | GNUNET_HELPER_send_cancel (struct GNUNET_HELPER_SendHandle *sh) | ||
655 | { | ||
656 | struct GNUNET_HELPER_Handle *h = sh->h; | ||
657 | |||
658 | sh->cont = NULL; | ||
659 | sh->cont_cls = NULL; | ||
660 | if (0 == sh->wpos) | ||
661 | { | ||
662 | GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh); | ||
663 | GNUNET_free (sh); | ||
664 | if (NULL == h->sh_head) | ||
665 | { | ||
666 | GNUNET_SCHEDULER_cancel (h->write_task); | ||
667 | h->write_task = NULL; | ||
668 | } | ||
669 | } | ||
670 | } | ||
671 | |||
672 | |||
673 | /* end of helper.c */ | ||