1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2022 OpenVPN Inc <sales@openvpn.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24 /*
25 * These routines implement a reliability layer on top of UDP,
26 * so that SSL/TLS can be run over UDP.
27 */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #elif defined(_MSC_VER)
32 #include "config-msvc.h"
33 #endif
34
35 #include "syshead.h"
36
37 #include "buffer.h"
38 #include "error.h"
39 #include "common.h"
40 #include "reliable.h"
41
42 #include "memdbg.h"
43
44 /*
45 * verify that test - base < extent while allowing for base or test wraparound
46 */
47 static inline bool
reliable_pid_in_range1(const packet_id_type test,const packet_id_type base,const unsigned int extent)48 reliable_pid_in_range1(const packet_id_type test,
49 const packet_id_type base,
50 const unsigned int extent)
51 {
52 if (test >= base)
53 {
54 if (test - base < extent)
55 {
56 return true;
57 }
58 }
59 else
60 {
61 if ((test+0x80000000u) - (base+0x80000000u) < extent)
62 {
63 return true;
64 }
65 }
66
67 return false;
68 }
69
70 /*
71 * verify that test < base + extent while allowing for base or test wraparound
72 */
73 static inline bool
reliable_pid_in_range2(const packet_id_type test,const packet_id_type base,const unsigned int extent)74 reliable_pid_in_range2(const packet_id_type test,
75 const packet_id_type base,
76 const unsigned int extent)
77 {
78 if (base + extent >= base)
79 {
80 if (test < base + extent)
81 {
82 return true;
83 }
84 }
85 else
86 {
87 if ((test+0x80000000u) < (base+0x80000000u) + extent)
88 {
89 return true;
90 }
91 }
92
93 return false;
94 }
95
96 /*
97 * verify that p1 < p2 while allowing for p1 or p2 wraparound
98 */
99 static inline bool
reliable_pid_min(const packet_id_type p1,const packet_id_type p2)100 reliable_pid_min(const packet_id_type p1,
101 const packet_id_type p2)
102 {
103 return !reliable_pid_in_range1(p1, p2, 0x80000000u);
104 }
105
106 /* check if a particular packet_id is present in ack */
107 static inline bool
reliable_ack_packet_id_present(struct reliable_ack * ack,packet_id_type pid)108 reliable_ack_packet_id_present(struct reliable_ack *ack, packet_id_type pid)
109 {
110 int i;
111 for (i = 0; i < ack->len; ++i)
112 {
113 if (ack->packet_id[i] == pid)
114 {
115 return true;
116 }
117 }
118 return false;
119 }
120
121 /* get a packet_id from buf */
122 bool
reliable_ack_read_packet_id(struct buffer * buf,packet_id_type * pid)123 reliable_ack_read_packet_id(struct buffer *buf, packet_id_type *pid)
124 {
125 packet_id_type net_pid;
126
127 if (buf_read(buf, &net_pid, sizeof(net_pid)))
128 {
129 *pid = ntohpid(net_pid);
130 dmsg(D_REL_DEBUG, "ACK read ID " packet_id_format " (buf->len=%d)",
131 (packet_id_print_type)*pid, buf->len);
132 return true;
133 }
134
135 dmsg(D_REL_LOW, "ACK read ID FAILED (buf->len=%d)", buf->len);
136 return false;
137 }
138
139 /* acknowledge a packet_id by adding it to a struct reliable_ack */
140 bool
reliable_ack_acknowledge_packet_id(struct reliable_ack * ack,packet_id_type pid)141 reliable_ack_acknowledge_packet_id(struct reliable_ack *ack, packet_id_type pid)
142 {
143 if (!reliable_ack_packet_id_present(ack, pid) && ack->len < RELIABLE_ACK_SIZE)
144 {
145 ack->packet_id[ack->len++] = pid;
146 dmsg(D_REL_DEBUG, "ACK acknowledge ID " packet_id_format " (ack->len=%d)",
147 (packet_id_print_type)pid, ack->len);
148 return true;
149 }
150
151 dmsg(D_REL_LOW, "ACK acknowledge ID " packet_id_format " FAILED (ack->len=%d)",
152 (packet_id_print_type)pid, ack->len);
153 return false;
154 }
155
156 /* read a packet ID acknowledgement record from buf into ack */
157 bool
reliable_ack_read(struct reliable_ack * ack,struct buffer * buf,const struct session_id * sid)158 reliable_ack_read(struct reliable_ack *ack,
159 struct buffer *buf, const struct session_id *sid)
160 {
161 struct gc_arena gc = gc_new();
162 int i;
163 uint8_t count;
164 packet_id_type net_pid;
165 packet_id_type pid;
166 struct session_id session_id_remote;
167
168 if (!buf_read(buf, &count, sizeof(count)))
169 {
170 goto error;
171 }
172 for (i = 0; i < count; ++i)
173 {
174 if (!buf_read(buf, &net_pid, sizeof(net_pid)))
175 {
176 goto error;
177 }
178 if (ack->len >= RELIABLE_ACK_SIZE)
179 {
180 goto error;
181 }
182 pid = ntohpid(net_pid);
183 ack->packet_id[ack->len++] = pid;
184 }
185 if (count)
186 {
187 if (!session_id_read(&session_id_remote, buf))
188 {
189 goto error;
190 }
191 if (!session_id_defined(&session_id_remote)
192 || !session_id_equal(&session_id_remote, sid))
193 {
194 dmsg(D_REL_LOW,
195 "ACK read BAD SESSION-ID FROM REMOTE, local=%s, remote=%s",
196 session_id_print(sid, &gc), session_id_print(&session_id_remote, &gc));
197 goto error;
198 }
199 }
200 gc_free(&gc);
201 return true;
202
203 error:
204 gc_free(&gc);
205 return false;
206 }
207
208 #define ACK_SIZE(n) (sizeof(uint8_t) + ((n) ? SID_SIZE : 0) + sizeof(packet_id_type) * (n))
209
210 /* write a packet ID acknowledgement record to buf, */
211 /* removing all acknowledged entries from ack */
212 bool
reliable_ack_write(struct reliable_ack * ack,struct buffer * buf,const struct session_id * sid,int max,bool prepend)213 reliable_ack_write(struct reliable_ack *ack,
214 struct buffer *buf,
215 const struct session_id *sid, int max, bool prepend)
216 {
217 int i, j;
218 uint8_t n;
219 struct buffer sub;
220
221 n = ack->len;
222 if (n > max)
223 {
224 n = max;
225 }
226 sub = buf_sub(buf, ACK_SIZE(n), prepend);
227 if (!BDEF(&sub))
228 {
229 goto error;
230 }
231 ASSERT(buf_write(&sub, &n, sizeof(n)));
232 for (i = 0; i < n; ++i)
233 {
234 packet_id_type pid = ack->packet_id[i];
235 packet_id_type net_pid = htonpid(pid);
236 ASSERT(buf_write(&sub, &net_pid, sizeof(net_pid)));
237 dmsg(D_REL_DEBUG, "ACK write ID " packet_id_format " (ack->len=%d, n=%d)", (packet_id_print_type)pid, ack->len, n);
238 }
239 if (n)
240 {
241 ASSERT(session_id_defined(sid));
242 ASSERT(session_id_write(sid, &sub));
243 for (i = 0, j = n; j < ack->len; )
244 {
245 ack->packet_id[i++] = ack->packet_id[j++];
246 }
247 ack->len = i;
248 }
249
250 return true;
251
252 error:
253 return false;
254 }
255
256 /* add to extra_frame the maximum number of bytes we will need for reliable_ack_write */
257 void
reliable_ack_adjust_frame_parameters(struct frame * frame,int max)258 reliable_ack_adjust_frame_parameters(struct frame *frame, int max)
259 {
260 frame_add_to_extra_frame(frame, ACK_SIZE(max));
261 }
262
263 /* print a reliable ACK record coming off the wire */
264 const char *
reliable_ack_print(struct buffer * buf,bool verbose,struct gc_arena * gc)265 reliable_ack_print(struct buffer *buf, bool verbose, struct gc_arena *gc)
266 {
267 int i;
268 uint8_t n_ack;
269 struct session_id sid_ack;
270 packet_id_type pid;
271 struct buffer out = alloc_buf_gc(256, gc);
272
273 buf_printf(&out, "[");
274 if (!buf_read(buf, &n_ack, sizeof(n_ack)))
275 {
276 goto done;
277 }
278 for (i = 0; i < n_ack; ++i)
279 {
280 if (!buf_read(buf, &pid, sizeof(pid)))
281 {
282 goto done;
283 }
284 pid = ntohpid(pid);
285 buf_printf(&out, " " packet_id_format, (packet_id_print_type)pid);
286 }
287 if (n_ack)
288 {
289 if (!session_id_read(&sid_ack, buf))
290 {
291 goto done;
292 }
293 if (verbose)
294 {
295 buf_printf(&out, " sid=%s", session_id_print(&sid_ack, gc));
296 }
297 }
298
299 done:
300 buf_printf(&out, " ]");
301 return BSTR(&out);
302 }
303
304 /*
305 * struct reliable member functions.
306 */
307
308 void
reliable_init(struct reliable * rel,int buf_size,int offset,int array_size,bool hold)309 reliable_init(struct reliable *rel, int buf_size, int offset, int array_size, bool hold)
310 {
311 int i;
312
313 CLEAR(*rel);
314 ASSERT(array_size > 0 && array_size <= RELIABLE_CAPACITY);
315 rel->hold = hold;
316 rel->size = array_size;
317 rel->offset = offset;
318 for (i = 0; i < rel->size; ++i)
319 {
320 struct reliable_entry *e = &rel->array[i];
321 e->buf = alloc_buf(buf_size);
322 ASSERT(buf_init(&e->buf, offset));
323 }
324 }
325
326 void
reliable_free(struct reliable * rel)327 reliable_free(struct reliable *rel)
328 {
329 int i;
330 for (i = 0; i < rel->size; ++i)
331 {
332 struct reliable_entry *e = &rel->array[i];
333 free_buf(&e->buf);
334 }
335 }
336
337 /* no active buffers? */
338 bool
reliable_empty(const struct reliable * rel)339 reliable_empty(const struct reliable *rel)
340 {
341 int i;
342 for (i = 0; i < rel->size; ++i)
343 {
344 const struct reliable_entry *e = &rel->array[i];
345 if (e->active)
346 {
347 return false;
348 }
349 }
350 return true;
351 }
352
353 /* del acknowledged items from send buf */
354 void
reliable_send_purge(struct reliable * rel,const struct reliable_ack * ack)355 reliable_send_purge(struct reliable *rel, const struct reliable_ack *ack)
356 {
357 int i, j;
358 for (i = 0; i < ack->len; ++i)
359 {
360 packet_id_type pid = ack->packet_id[i];
361 for (j = 0; j < rel->size; ++j)
362 {
363 struct reliable_entry *e = &rel->array[j];
364 if (e->active && e->packet_id == pid)
365 {
366 dmsg(D_REL_DEBUG,
367 "ACK received for pid " packet_id_format ", deleting from send buffer",
368 (packet_id_print_type)pid);
369 #if 0
370 /* DEBUGGING -- how close were we timing out on ACK failure and resending? */
371 {
372 if (e->next_try)
373 {
374 const interval_t wake = e->next_try - now;
375 msg(M_INFO, "ACK " packet_id_format ", wake=%d", pid, wake);
376 }
377 }
378 #endif
379 e->active = false;
380 break;
381 }
382 }
383 }
384 }
385
386 /* print the current sequence of active packet IDs */
387 static const char *
reliable_print_ids(const struct reliable * rel,struct gc_arena * gc)388 reliable_print_ids(const struct reliable *rel, struct gc_arena *gc)
389 {
390 struct buffer out = alloc_buf_gc(256, gc);
391 int i;
392
393 buf_printf(&out, "[" packet_id_format "]", (packet_id_print_type)rel->packet_id);
394 for (i = 0; i < rel->size; ++i)
395 {
396 const struct reliable_entry *e = &rel->array[i];
397 if (e->active)
398 {
399 buf_printf(&out, " " packet_id_format, (packet_id_print_type)e->packet_id);
400 }
401 }
402 return BSTR(&out);
403 }
404
405 /* true if at least one free buffer available */
406 bool
reliable_can_get(const struct reliable * rel)407 reliable_can_get(const struct reliable *rel)
408 {
409 struct gc_arena gc = gc_new();
410 int i;
411 for (i = 0; i < rel->size; ++i)
412 {
413 const struct reliable_entry *e = &rel->array[i];
414 if (!e->active)
415 {
416 return true;
417 }
418 }
419 dmsg(D_REL_LOW, "ACK no free receive buffer available: %s", reliable_print_ids(rel, &gc));
420 gc_free(&gc);
421 return false;
422 }
423
424 /* make sure that incoming packet ID isn't a replay */
425 bool
reliable_not_replay(const struct reliable * rel,packet_id_type id)426 reliable_not_replay(const struct reliable *rel, packet_id_type id)
427 {
428 struct gc_arena gc = gc_new();
429 int i;
430 if (reliable_pid_min(id, rel->packet_id))
431 {
432 goto bad;
433 }
434 for (i = 0; i < rel->size; ++i)
435 {
436 const struct reliable_entry *e = &rel->array[i];
437 if (e->active && e->packet_id == id)
438 {
439 goto bad;
440 }
441 }
442 gc_free(&gc);
443 return true;
444
445 bad:
446 dmsg(D_REL_DEBUG, "ACK " packet_id_format " is a replay: %s", (packet_id_print_type)id, reliable_print_ids(rel, &gc));
447 gc_free(&gc);
448 return false;
449 }
450
451 /* make sure that incoming packet ID won't deadlock the receive buffer */
452 bool
reliable_wont_break_sequentiality(const struct reliable * rel,packet_id_type id)453 reliable_wont_break_sequentiality(const struct reliable *rel, packet_id_type id)
454 {
455 struct gc_arena gc = gc_new();
456
457 const int ret = reliable_pid_in_range2(id, rel->packet_id, rel->size);
458
459 if (!ret)
460 {
461 dmsg(D_REL_LOW, "ACK " packet_id_format " breaks sequentiality: %s",
462 (packet_id_print_type)id, reliable_print_ids(rel, &gc));
463 }
464
465 dmsg(D_REL_DEBUG, "ACK RWBS rel->size=%d rel->packet_id=%08x id=%08x ret=%d", rel->size, rel->packet_id, id, ret);
466
467 gc_free(&gc);
468 return ret;
469 }
470
471 /* grab a free buffer */
472 struct buffer *
reliable_get_buf(struct reliable * rel)473 reliable_get_buf(struct reliable *rel)
474 {
475 int i;
476 for (i = 0; i < rel->size; ++i)
477 {
478 struct reliable_entry *e = &rel->array[i];
479 if (!e->active)
480 {
481 ASSERT(buf_init(&e->buf, rel->offset));
482 return &e->buf;
483 }
484 }
485 return NULL;
486 }
487
488 /* grab a free buffer, fail if buffer clogged by unacknowledged low packet IDs */
489 struct buffer *
reliable_get_buf_output_sequenced(struct reliable * rel)490 reliable_get_buf_output_sequenced(struct reliable *rel)
491 {
492 struct gc_arena gc = gc_new();
493 int i;
494 packet_id_type min_id = 0;
495 bool min_id_defined = false;
496 struct buffer *ret = NULL;
497
498 /* find minimum active packet_id */
499 for (i = 0; i < rel->size; ++i)
500 {
501 const struct reliable_entry *e = &rel->array[i];
502 if (e->active)
503 {
504 if (!min_id_defined || reliable_pid_min(e->packet_id, min_id))
505 {
506 min_id_defined = true;
507 min_id = e->packet_id;
508 }
509 }
510 }
511
512 if (!min_id_defined || reliable_pid_in_range1(rel->packet_id, min_id, rel->size))
513 {
514 ret = reliable_get_buf(rel);
515 }
516 else
517 {
518 dmsg(D_REL_LOW, "ACK output sequence broken: %s", reliable_print_ids(rel, &gc));
519 }
520 gc_free(&gc);
521 return ret;
522 }
523
524 /* get active buffer for next sequentially increasing key ID */
525 struct buffer *
reliable_get_buf_sequenced(struct reliable * rel)526 reliable_get_buf_sequenced(struct reliable *rel)
527 {
528 int i;
529 for (i = 0; i < rel->size; ++i)
530 {
531 struct reliable_entry *e = &rel->array[i];
532 if (e->active && e->packet_id == rel->packet_id)
533 {
534 return &e->buf;
535 }
536 }
537 return NULL;
538 }
539
540 /* return true if reliable_send would return a non-NULL result */
541 bool
reliable_can_send(const struct reliable * rel)542 reliable_can_send(const struct reliable *rel)
543 {
544 struct gc_arena gc = gc_new();
545 int i;
546 int n_active = 0, n_current = 0;
547 for (i = 0; i < rel->size; ++i)
548 {
549 const struct reliable_entry *e = &rel->array[i];
550 if (e->active)
551 {
552 ++n_active;
553 if (now >= e->next_try)
554 {
555 ++n_current;
556 }
557 }
558 }
559 dmsg(D_REL_DEBUG, "ACK reliable_can_send active=%d current=%d : %s",
560 n_active,
561 n_current,
562 reliable_print_ids(rel, &gc));
563
564 gc_free(&gc);
565 return n_current > 0 && !rel->hold;
566 }
567
568 /* return next buffer to send to remote */
569 struct buffer *
reliable_send(struct reliable * rel,int * opcode)570 reliable_send(struct reliable *rel, int *opcode)
571 {
572 int i;
573 struct reliable_entry *best = NULL;
574 const time_t local_now = now;
575
576 for (i = 0; i < rel->size; ++i)
577 {
578 struct reliable_entry *e = &rel->array[i];
579 if (e->active && local_now >= e->next_try)
580 {
581 if (!best || reliable_pid_min(e->packet_id, best->packet_id))
582 {
583 best = e;
584 }
585 }
586 }
587 if (best)
588 {
589 #ifdef EXPONENTIAL_BACKOFF
590 /* exponential backoff */
591 best->next_try = local_now + best->timeout;
592 best->timeout *= 2;
593 #else
594 /* constant timeout, no backoff */
595 best->next_try = local_now + best->timeout;
596 #endif
597 *opcode = best->opcode;
598 dmsg(D_REL_DEBUG, "ACK reliable_send ID " packet_id_format " (size=%d to=%d)",
599 (packet_id_print_type)best->packet_id, best->buf.len,
600 (int)(best->next_try - local_now));
601 return &best->buf;
602 }
603 return NULL;
604 }
605
606 /* schedule all pending packets for immediate retransmit */
607 void
reliable_schedule_now(struct reliable * rel)608 reliable_schedule_now(struct reliable *rel)
609 {
610 int i;
611 dmsg(D_REL_DEBUG, "ACK reliable_schedule_now");
612 rel->hold = false;
613 for (i = 0; i < rel->size; ++i)
614 {
615 struct reliable_entry *e = &rel->array[i];
616 if (e->active)
617 {
618 e->next_try = now;
619 e->timeout = rel->initial_timeout;
620 }
621 }
622 }
623
624 /* in how many seconds should we wake up to check for timeout */
625 /* if we return BIG_TIMEOUT, nothing to wait for */
626 interval_t
reliable_send_timeout(const struct reliable * rel)627 reliable_send_timeout(const struct reliable *rel)
628 {
629 struct gc_arena gc = gc_new();
630 interval_t ret = BIG_TIMEOUT;
631 int i;
632 const time_t local_now = now;
633
634 for (i = 0; i < rel->size; ++i)
635 {
636 const struct reliable_entry *e = &rel->array[i];
637 if (e->active)
638 {
639 if (e->next_try <= local_now)
640 {
641 ret = 0;
642 break;
643 }
644 else
645 {
646 ret = min_int(ret, e->next_try - local_now);
647 }
648 }
649 }
650
651 dmsg(D_REL_DEBUG, "ACK reliable_send_timeout %d %s",
652 (int) ret,
653 reliable_print_ids(rel, &gc));
654
655 gc_free(&gc);
656 return ret;
657 }
658
659 /*
660 * Enable an incoming buffer previously returned by a get function as active.
661 */
662
663 void
reliable_mark_active_incoming(struct reliable * rel,struct buffer * buf,packet_id_type pid,int opcode)664 reliable_mark_active_incoming(struct reliable *rel, struct buffer *buf,
665 packet_id_type pid, int opcode)
666 {
667 int i;
668 for (i = 0; i < rel->size; ++i)
669 {
670 struct reliable_entry *e = &rel->array[i];
671 if (buf == &e->buf)
672 {
673 e->active = true;
674
675 /* packets may not arrive in sequential order */
676 e->packet_id = pid;
677
678 /* check for replay */
679 ASSERT(!reliable_pid_min(pid, rel->packet_id));
680
681 e->opcode = opcode;
682 e->next_try = 0;
683 e->timeout = 0;
684 dmsg(D_REL_DEBUG, "ACK mark active incoming ID " packet_id_format, (packet_id_print_type)e->packet_id);
685 return;
686 }
687 }
688 ASSERT(0); /* buf not found in rel */
689 }
690
691 /*
692 * Enable an outgoing buffer previously returned by a get function as active.
693 */
694
695 void
reliable_mark_active_outgoing(struct reliable * rel,struct buffer * buf,int opcode)696 reliable_mark_active_outgoing(struct reliable *rel, struct buffer *buf, int opcode)
697 {
698 int i;
699 for (i = 0; i < rel->size; ++i)
700 {
701 struct reliable_entry *e = &rel->array[i];
702 if (buf == &e->buf)
703 {
704 /* Write mode, increment packet_id (i.e. sequence number)
705 * linearly and prepend id to packet */
706 packet_id_type net_pid;
707 e->packet_id = rel->packet_id++;
708 net_pid = htonpid(e->packet_id);
709 ASSERT(buf_write_prepend(buf, &net_pid, sizeof(net_pid)));
710 e->active = true;
711 e->opcode = opcode;
712 e->next_try = 0;
713 e->timeout = rel->initial_timeout;
714 dmsg(D_REL_DEBUG, "ACK mark active outgoing ID " packet_id_format, (packet_id_print_type)e->packet_id);
715 return;
716 }
717 }
718 ASSERT(0); /* buf not found in rel */
719 }
720
721 /* delete a buffer previously activated by reliable_mark_active() */
722 void
reliable_mark_deleted(struct reliable * rel,struct buffer * buf,bool inc_pid)723 reliable_mark_deleted(struct reliable *rel, struct buffer *buf, bool inc_pid)
724 {
725 int i;
726 for (i = 0; i < rel->size; ++i)
727 {
728 struct reliable_entry *e = &rel->array[i];
729 if (buf == &e->buf)
730 {
731 e->active = false;
732 if (inc_pid)
733 {
734 rel->packet_id = e->packet_id + 1;
735 }
736 return;
737 }
738 }
739 ASSERT(0);
740 }
741
742 #if 0
743
744 void
745 reliable_ack_debug_print(const struct reliable_ack *ack, char *desc)
746 {
747 int i;
748
749 printf("********* struct reliable_ack %s\n", desc);
750 for (i = 0; i < ack->len; ++i)
751 {
752 printf(" %d: " packet_id_format "\n", i, (packet_id_print_type) ack->packet_id[i]);
753 }
754 }
755
756 void
757 reliable_debug_print(const struct reliable *rel, char *desc)
758 {
759 int i;
760 update_time();
761
762 printf("********* struct reliable %s\n", desc);
763 printf(" initial_timeout=%d\n", (int)rel->initial_timeout);
764 printf(" packet_id=" packet_id_format "\n", rel->packet_id);
765 printf(" now=%" PRIi64 "\n", (int64_t)now);
766 for (i = 0; i < rel->size; ++i)
767 {
768 const struct reliable_entry *e = &rel->array[i];
769 if (e->active)
770 {
771 printf(" %d: packet_id=" packet_id_format " len=%d", i, e->packet_id, e->buf.len);
772 printf(" next_try=%" PRIi64, (int64_t)e->next_try);
773 printf("\n");
774 }
775 }
776 }
777
778 #endif /* if 0 */
779