Coverage Report

Created: 2026-11-12 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openiked-portable/compat/imsg-buffer.c
Line
Count
Source
1
/*  $OpenBSD: imsg-buffer.c,v 1.37 2026/05/12 16:01:15 claudio Exp $  */
2
3
/*
4
 * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
5
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <sys/types.h>
21
#include <sys/queue.h>
22
#include <sys/socket.h>
23
#include <sys/uio.h>
24
25
#include <limits.h>
26
#include <errno.h>
27
#include <endian.h>
28
#include <stdint.h>
29
#include <stdlib.h>
30
#include <string.h>
31
#include <unistd.h>
32
33
#include "openbsd-compat.h"
34
#include "imsg.h"
35
36
struct ibufqueue {
37
  TAILQ_HEAD(, ibuf)  bufs;
38
  uint32_t    queued;
39
};
40
41
struct msgbuf {
42
  struct ibufqueue   bufs;
43
  struct ibufqueue   rbufs;
44
  char      *rbuf;
45
  struct ibuf   *rpmsg;
46
  struct ibuf   *(*readhdr)(struct ibuf *, void *, int *);
47
  void      *rarg;
48
  size_t       roff;
49
  size_t       hdrsize;
50
};
51
52
static void msgbuf_drain(struct msgbuf *, size_t);
53
static void ibufq_init(struct ibufqueue *);
54
55
12.6k
#define IBUF_FD_MARK_ON_STACK -2
56
57
struct ibuf *
58
ibuf_open(size_t len)
59
0
{
60
0
  struct ibuf *buf;
61
62
0
  if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
63
0
    return (NULL);
64
0
  if (len > 0) {
65
0
    if ((buf->buf = calloc(len, 1)) == NULL) {
66
0
      free(buf);
67
0
      return (NULL);
68
0
    }
69
0
  }
70
0
  buf->size = buf->max = len;
71
0
  buf->fd = -1;
72
73
0
  return (buf);
74
0
}
75
76
struct ibuf *
77
ibuf_dynamic(size_t len, size_t max)
78
7.57k
{
79
7.57k
  struct ibuf *buf;
80
81
7.57k
  if (max == 0 || max < len) {
82
0
    errno = EINVAL;
83
0
    return (NULL);
84
0
  }
85
86
7.57k
  if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
87
0
    return (NULL);
88
7.57k
  if (len > 0) {
89
5.06k
    if ((buf->buf = calloc(len, 1)) == NULL) {
90
0
      free(buf);
91
0
      return (NULL);
92
0
    }
93
5.06k
  }
94
7.57k
  buf->size = len;
95
7.57k
  buf->max = max;
96
7.57k
  buf->fd = -1;
97
98
7.57k
  return (buf);
99
7.57k
}
100
101
void *
102
ibuf_reserve(struct ibuf *buf, size_t len)
103
5.06k
{
104
5.06k
  void  *b;
105
106
5.06k
  if (len > SIZE_MAX - buf->wpos) {
107
0
    errno = ERANGE;
108
0
    return (NULL);
109
0
  }
110
5.06k
  if (buf->fd == IBUF_FD_MARK_ON_STACK) {
111
    /* can not grow stack buffers */
112
0
    errno = EINVAL;
113
0
    return (NULL);
114
0
  }
115
116
5.06k
  if (buf->wpos + len > buf->size) {
117
0
    unsigned char *nb;
118
119
    /* check if buffer is allowed to grow */
120
0
    if (buf->wpos + len > buf->max) {
121
0
      errno = ERANGE;
122
0
      return (NULL);
123
0
    }
124
0
    nb = realloc(buf->buf, buf->wpos + len);
125
0
    if (nb == NULL)
126
0
      return (NULL);
127
0
    memset(nb + buf->size, 0, buf->wpos + len - buf->size);
128
0
    buf->buf = nb;
129
0
    buf->size = buf->wpos + len;
130
0
  }
131
132
5.06k
  b = buf->buf + buf->wpos;
133
5.06k
  buf->wpos += len;
134
5.06k
  return (b);
135
5.06k
}
136
137
int
138
ibuf_add(struct ibuf *buf, const void *data, size_t len)
139
5.04k
{
140
5.04k
  void *b;
141
142
5.04k
  if (len == 0)
143
0
    return (0);
144
145
5.04k
  if ((b = ibuf_reserve(buf, len)) == NULL)
146
0
    return (-1);
147
148
5.04k
  memcpy(b, data, len);
149
5.04k
  return (0);
150
5.04k
}
151
152
int
153
ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
154
0
{
155
0
  return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
156
0
}
157
158
int
159
ibuf_add_n8(struct ibuf *buf, uint64_t value)
160
0
{
161
0
  uint8_t v;
162
163
0
  if (value > UINT8_MAX) {
164
0
    errno = EINVAL;
165
0
    return (-1);
166
0
  }
167
0
  v = value;
168
0
  return ibuf_add(buf, &v, sizeof(v));
169
0
}
170
171
int
172
ibuf_add_n16(struct ibuf *buf, uint64_t value)
173
0
{
174
0
  uint16_t v;
175
176
0
  if (value > UINT16_MAX) {
177
0
    errno = EINVAL;
178
0
    return (-1);
179
0
  }
180
0
  v = htobe16(value);
181
0
  return ibuf_add(buf, &v, sizeof(v));
182
0
}
183
184
int
185
ibuf_add_n32(struct ibuf *buf, uint64_t value)
186
0
{
187
0
  uint32_t v;
188
189
0
  if (value > UINT32_MAX) {
190
0
    errno = EINVAL;
191
0
    return (-1);
192
0
  }
193
0
  v = htobe32(value);
194
0
  return ibuf_add(buf, &v, sizeof(v));
195
0
}
196
197
int
198
ibuf_add_n64(struct ibuf *buf, uint64_t value)
199
0
{
200
0
  value = htobe64(value);
201
0
  return ibuf_add(buf, &value, sizeof(value));
202
0
}
203
204
int
205
ibuf_add_h16(struct ibuf *buf, uint64_t value)
206
0
{
207
0
  uint16_t v;
208
209
0
  if (value > UINT16_MAX) {
210
0
    errno = EINVAL;
211
0
    return (-1);
212
0
  }
213
0
  v = value;
214
0
  return ibuf_add(buf, &v, sizeof(v));
215
0
}
216
217
int
218
ibuf_add_h32(struct ibuf *buf, uint64_t value)
219
0
{
220
0
  uint32_t v;
221
222
0
  if (value > UINT32_MAX) {
223
0
    errno = EINVAL;
224
0
    return (-1);
225
0
  }
226
0
  v = value;
227
0
  return ibuf_add(buf, &v, sizeof(v));
228
0
}
229
230
int
231
ibuf_add_h64(struct ibuf *buf, uint64_t value)
232
0
{
233
0
  return ibuf_add(buf, &value, sizeof(value));
234
0
}
235
236
int
237
ibuf_add_zero(struct ibuf *buf, size_t len)
238
20
{
239
20
  void *b;
240
241
20
  if (len == 0)
242
0
    return (0);
243
244
20
  if ((b = ibuf_reserve(buf, len)) == NULL)
245
0
    return (-1);
246
20
  memset(b, 0, len);
247
20
  return (0);
248
20
}
249
250
int
251
ibuf_add_strbuf(struct ibuf *buf, const char *str, size_t len)
252
0
{
253
0
  char *b;
254
0
  size_t n;
255
256
0
  if ((b = ibuf_reserve(buf, len)) == NULL)
257
0
    return (-1);
258
259
0
  n = strlcpy(b, str, len);
260
0
  if (n >= len) {
261
    /* also covers the case where len == 0 */
262
0
    errno = EOVERFLOW;
263
0
    return (-1);
264
0
  }
265
0
  memset(b + n, 0, len - n);
266
0
  return (0);
267
0
}
268
269
void *
270
ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
271
46.7k
{
272
  /* only allow seeking between rpos and wpos */
273
46.7k
  if (ibuf_size(buf) < pos || SIZE_MAX - pos < len ||
274
46.7k
      ibuf_size(buf) < pos + len) {
275
0
    errno = ERANGE;
276
0
    return (NULL);
277
0
  }
278
279
46.7k
  return (buf->buf + buf->rpos + pos);
280
46.7k
}
281
282
int
283
ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
284
0
{
285
0
  void *b;
286
287
0
  if ((b = ibuf_seek(buf, pos, len)) == NULL)
288
0
    return (-1);
289
290
0
  if (len == 0)
291
0
    return (0);
292
0
  memcpy(b, data, len);
293
0
  return (0);
294
0
}
295
296
int
297
ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value)
298
0
{
299
0
  uint8_t v;
300
301
0
  if (value > UINT8_MAX) {
302
0
    errno = EINVAL;
303
0
    return (-1);
304
0
  }
305
0
  v = value;
306
0
  return (ibuf_set(buf, pos, &v, sizeof(v)));
307
0
}
308
309
int
310
ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value)
311
0
{
312
0
  uint16_t v;
313
314
0
  if (value > UINT16_MAX) {
315
0
    errno = EINVAL;
316
0
    return (-1);
317
0
  }
318
0
  v = htobe16(value);
319
0
  return (ibuf_set(buf, pos, &v, sizeof(v)));
320
0
}
321
322
int
323
ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value)
324
0
{
325
0
  uint32_t v;
326
327
0
  if (value > UINT32_MAX) {
328
0
    errno = EINVAL;
329
0
    return (-1);
330
0
  }
331
0
  v = htobe32(value);
332
0
  return (ibuf_set(buf, pos, &v, sizeof(v)));
333
0
}
334
335
int
336
ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
337
0
{
338
0
  value = htobe64(value);
339
0
  return (ibuf_set(buf, pos, &value, sizeof(value)));
340
0
}
341
342
int
343
ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value)
344
0
{
345
0
  uint16_t v;
346
347
0
  if (value > UINT16_MAX) {
348
0
    errno = EINVAL;
349
0
    return (-1);
350
0
  }
351
0
  v = value;
352
0
  return (ibuf_set(buf, pos, &v, sizeof(v)));
353
0
}
354
355
int
356
ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value)
357
0
{
358
0
  uint32_t v;
359
360
0
  if (value > UINT32_MAX) {
361
0
    errno = EINVAL;
362
0
    return (-1);
363
0
  }
364
0
  v = value;
365
0
  return (ibuf_set(buf, pos, &v, sizeof(v)));
366
0
}
367
368
int
369
ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value)
370
0
{
371
0
  return (ibuf_set(buf, pos, &value, sizeof(value)));
372
0
}
373
374
int
375
ibuf_set_maxsize(struct ibuf *buf, size_t max)
376
0
{
377
0
  if (buf->fd == IBUF_FD_MARK_ON_STACK) {
378
    /* can't fiddle with stack buffers */
379
0
    errno = EINVAL;
380
0
    return (-1);
381
0
  }
382
0
  if (max > buf->max) { /* can only shrink the buffer */
383
0
    errno = ERANGE;
384
0
    return (-1);
385
0
  }
386
0
  if (buf->wpos > max) { /* cannot shrink below current wpos */
387
0
    errno = ERANGE;
388
0
    return (-1);
389
0
  }
390
0
  if (buf->size > max) { /* clear excess memory */
391
0
    explicit_bzero(buf->buf + max, buf->size - max);
392
0
    buf->size = max;
393
0
  }
394
  
395
0
  buf->max = max;
396
0
  return (0);
397
0
}
398
399
void *
400
ibuf_data(const struct ibuf *buf)
401
124k
{
402
124k
  return (buf->buf + buf->rpos);
403
124k
}
404
405
size_t
406
ibuf_size(const struct ibuf *buf)
407
97.2k
{
408
97.2k
  return (buf->wpos - buf->rpos);
409
97.2k
}
410
411
size_t
412
ibuf_left(const struct ibuf *buf)
413
0
{
414
  /* on stack buffers have no space left */
415
0
  if (buf->fd == IBUF_FD_MARK_ON_STACK)
416
0
    return (0);
417
0
  return (buf->max - buf->wpos);
418
0
}
419
420
int
421
ibuf_truncate(struct ibuf *buf, size_t len)
422
0
{
423
0
  if (ibuf_size(buf) >= len) {
424
0
    buf->wpos = buf->rpos + len;
425
0
    return (0);
426
0
  }
427
0
  if (buf->fd == IBUF_FD_MARK_ON_STACK) {
428
    /* only allow to truncate down for stack buffers */
429
0
    errno = ERANGE;
430
0
    return (-1);
431
0
  }
432
0
  return ibuf_add_zero(buf, len - ibuf_size(buf));
433
0
}
434
435
void
436
ibuf_rewind(struct ibuf *buf)
437
0
{
438
0
  buf->rpos = 0;
439
0
}
440
441
void
442
ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
443
0
{
444
0
  ibufq_push(&msgbuf->bufs, buf);
445
0
}
446
447
void
448
ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
449
0
{
450
0
  memset(buf, 0, sizeof(*buf));
451
0
  buf->buf = data;
452
0
  buf->size = buf->wpos = len;
453
0
  buf->fd = IBUF_FD_MARK_ON_STACK;
454
0
}
455
456
void
457
ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from)
458
0
{
459
0
  ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from));
460
0
}
461
462
int
463
ibuf_get(struct ibuf *buf, void *data, size_t len)
464
0
{
465
0
  if (ibuf_size(buf) < len) {
466
0
    errno = EBADMSG;
467
0
    return (-1);
468
0
  }
469
470
0
  memcpy(data, ibuf_data(buf), len);
471
0
  buf->rpos += len;
472
0
  return (0);
473
0
}
474
475
int
476
ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
477
0
{
478
0
  if (ibuf_size(buf) < len) {
479
0
    errno = EBADMSG;
480
0
    return (-1);
481
0
  }
482
483
0
  ibuf_from_buffer(new, ibuf_data(buf), len);
484
0
  buf->rpos += len;
485
0
  return (0);
486
0
}
487
488
int
489
ibuf_get_h16(struct ibuf *buf, uint16_t *value)
490
0
{
491
0
  return ibuf_get(buf, value, sizeof(*value));
492
0
}
493
494
int
495
ibuf_get_h32(struct ibuf *buf, uint32_t *value)
496
0
{
497
0
  return ibuf_get(buf, value, sizeof(*value));
498
0
}
499
500
int
501
ibuf_get_h64(struct ibuf *buf, uint64_t *value)
502
0
{
503
0
  return ibuf_get(buf, value, sizeof(*value));
504
0
}
505
506
int
507
ibuf_get_n8(struct ibuf *buf, uint8_t *value)
508
0
{
509
0
  return ibuf_get(buf, value, sizeof(*value));
510
0
}
511
512
int
513
ibuf_get_n16(struct ibuf *buf, uint16_t *value)
514
0
{
515
0
  int rv;
516
517
0
  rv = ibuf_get(buf, value, sizeof(*value));
518
0
  *value = be16toh(*value);
519
0
  return (rv);
520
0
}
521
522
int
523
ibuf_get_n32(struct ibuf *buf, uint32_t *value)
524
0
{
525
0
  int rv;
526
527
0
  rv = ibuf_get(buf, value, sizeof(*value));
528
0
  *value = be32toh(*value);
529
0
  return (rv);
530
0
}
531
532
int
533
ibuf_get_n64(struct ibuf *buf, uint64_t *value)
534
0
{
535
0
  int rv;
536
537
0
  rv = ibuf_get(buf, value, sizeof(*value));
538
0
  *value = be64toh(*value);
539
0
  return (rv);
540
0
}
541
542
char *
543
ibuf_get_string(struct ibuf *buf, size_t len)
544
0
{
545
0
  char *str;
546
547
0
  if (ibuf_size(buf) < len) {
548
0
    errno = EBADMSG;
549
0
    return (NULL);
550
0
  }
551
552
0
  str = strndup(ibuf_data(buf), len);
553
0
  if (str == NULL)
554
0
    return (NULL);
555
0
  buf->rpos += len;
556
0
  return (str);
557
0
}
558
559
int
560
ibuf_get_strbuf(struct ibuf *buf, char *str, size_t len)
561
0
{
562
0
  if (len == 0) {
563
0
    errno = EINVAL;
564
0
    return (-1);
565
0
  }
566
567
0
  if (ibuf_get(buf, str, len) == -1)
568
0
    return -1;
569
0
  if (str[len - 1] != '\0') {
570
0
    str[len - 1] = '\0';
571
0
    errno = EOVERFLOW;
572
0
    return -1;
573
0
  }
574
0
  return 0;
575
0
}
576
577
int
578
ibuf_skip(struct ibuf *buf, size_t len)
579
0
{
580
0
  if (ibuf_size(buf) < len) {
581
0
    errno = EBADMSG;
582
0
    return (-1);
583
0
  }
584
585
0
  buf->rpos += len;
586
0
  return (0);
587
0
}
588
589
void
590
ibuf_free(struct ibuf *buf)
591
37.6k
{
592
37.6k
  int save_errno = errno;
593
594
37.6k
  if (buf == NULL)
595
30.1k
    return;
596
  /* if buf lives on the stack abort before causing more harm */
597
7.57k
  if (buf->fd == IBUF_FD_MARK_ON_STACK)
598
0
    abort();
599
7.57k
  if (buf->fd >= 0)
600
0
    close(buf->fd);
601
7.57k
  freezero(buf->buf, buf->size);
602
7.57k
  free(buf);
603
7.57k
  errno = save_errno;
604
7.57k
}
605
606
int
607
ibuf_fd_avail(struct ibuf *buf)
608
0
{
609
0
  return (buf->fd >= 0);
610
0
}
611
612
int
613
ibuf_fd_get(struct ibuf *buf)
614
0
{
615
0
  int fd;
616
617
  /* negative fds are internal use and equivalent to -1 */
618
0
  if (buf->fd < 0)
619
0
    return (-1);
620
0
  fd = buf->fd;
621
0
  buf->fd = -1;
622
0
  return (fd);
623
0
}
624
625
void
626
ibuf_fd_set(struct ibuf *buf, int fd)
627
0
{
628
  /* if buf lives on the stack abort before causing more harm */
629
0
  if (buf->fd == IBUF_FD_MARK_ON_STACK)
630
0
    abort();
631
0
  if (buf->fd >= 0)
632
0
    close(buf->fd);
633
0
  buf->fd = -1;
634
0
  if (fd >= 0)
635
0
    buf->fd = fd;
636
0
}
637
638
struct msgbuf *
639
msgbuf_new(void)
640
0
{
641
0
  struct msgbuf *msgbuf;
642
643
0
  if ((msgbuf = calloc(1, sizeof(*msgbuf))) == NULL)
644
0
    return (NULL);
645
0
  ibufq_init(&msgbuf->bufs);
646
0
  ibufq_init(&msgbuf->rbufs);
647
648
0
  return msgbuf;
649
0
}
650
651
struct msgbuf *
652
msgbuf_new_reader(size_t hdrsz,
653
    struct ibuf *(*readhdr)(struct ibuf *, void *, int *), void *arg)
654
0
{
655
0
  struct msgbuf *msgbuf;
656
0
  char *buf;
657
658
0
  if (hdrsz == 0 || hdrsz > IBUF_READ_SIZE / 2) {
659
0
    errno = EINVAL;
660
0
    return (NULL);
661
0
  }
662
663
0
  if ((buf = malloc(IBUF_READ_SIZE)) == NULL)
664
0
    return (NULL);
665
666
0
  msgbuf = msgbuf_new();
667
0
  if (msgbuf == NULL) {
668
0
    free(buf);
669
0
    return (NULL);
670
0
  }
671
672
0
  msgbuf->rbuf = buf;
673
0
  msgbuf->hdrsize = hdrsz;
674
0
  msgbuf->readhdr = readhdr;
675
0
  msgbuf->rarg = arg;
676
677
0
  return (msgbuf);
678
0
}
679
680
void
681
msgbuf_free(struct msgbuf *msgbuf)
682
0
{
683
0
  if (msgbuf == NULL)
684
0
    return;
685
0
  msgbuf_clear(msgbuf);
686
0
  free(msgbuf->rbuf);
687
0
  free(msgbuf);
688
0
}
689
690
uint32_t
691
msgbuf_queuelen(struct msgbuf *msgbuf)
692
0
{
693
0
  return ibufq_queuelen(&msgbuf->bufs);
694
0
}
695
696
void
697
msgbuf_clear(struct msgbuf *msgbuf)
698
0
{
699
  /* write side */
700
0
  ibufq_flush(&msgbuf->bufs);
701
702
  /* read side */
703
0
  ibufq_flush(&msgbuf->rbufs);
704
0
  msgbuf->roff = 0;
705
0
  ibuf_free(msgbuf->rpmsg);
706
0
  msgbuf->rpmsg = NULL;
707
0
}
708
709
struct ibuf *
710
msgbuf_get(struct msgbuf *msgbuf)
711
0
{
712
0
  return ibufq_pop(&msgbuf->rbufs);
713
0
}
714
715
void
716
msgbuf_concat(struct msgbuf *msgbuf, struct ibufqueue *from)
717
0
{
718
0
  ibufq_concat(&msgbuf->bufs, from);
719
0
}
720
721
int
722
ibuf_write(int fd, struct msgbuf *msgbuf)
723
0
{
724
0
  struct iovec   iov[IOV_MAX];
725
0
  struct ibuf *buf;
726
0
  unsigned int   i = 0;
727
0
  ssize_t n;
728
729
0
  memset(&iov, 0, sizeof(iov));
730
0
  TAILQ_FOREACH(buf, &msgbuf->bufs.bufs, entry) {
731
0
    if (i >= IOV_MAX)
732
0
      break;
733
0
    iov[i].iov_base = ibuf_data(buf);
734
0
    iov[i].iov_len = ibuf_size(buf);
735
0
    i++;
736
0
  }
737
0
  if (i == 0)
738
0
    return (0); /* nothing queued */
739
740
0
 again:
741
0
  if ((n = writev(fd, iov, i)) == -1) {
742
0
    if (errno == EINTR)
743
0
      goto again;
744
0
    if (errno == EAGAIN || errno == ENOBUFS)
745
      /* lets retry later again */
746
0
      return (0);
747
0
    return (-1);
748
0
  }
749
750
0
  msgbuf_drain(msgbuf, n);
751
0
  return (0);
752
0
}
753
754
int
755
msgbuf_write(int fd, struct msgbuf *msgbuf)
756
0
{
757
0
  struct iovec   iov[IOV_MAX];
758
0
  struct ibuf *buf, *buf0 = NULL;
759
0
  unsigned int   i = 0;
760
0
  ssize_t    n;
761
0
  struct msghdr  msg;
762
0
  struct cmsghdr  *cmsg;
763
0
  union {
764
0
    struct cmsghdr  hdr;
765
0
    char    buf[CMSG_SPACE(sizeof(int))];
766
0
  } cmsgbuf;
767
768
0
  memset(&iov, 0, sizeof(iov));
769
0
  memset(&msg, 0, sizeof(msg));
770
0
  memset(&cmsgbuf, 0, sizeof(cmsgbuf));
771
0
  TAILQ_FOREACH(buf, &msgbuf->bufs.bufs, entry) {
772
0
    if (i >= IOV_MAX)
773
0
      break;
774
0
    if (i > 0 && buf->fd != -1)
775
0
      break;
776
0
    iov[i].iov_base = ibuf_data(buf);
777
0
    iov[i].iov_len = ibuf_size(buf);
778
0
    i++;
779
0
    if (buf->fd != -1)
780
0
      buf0 = buf;
781
0
  }
782
783
0
  if (i == 0)
784
0
    return (0); /* nothing queued */
785
786
0
  msg.msg_iov = iov;
787
0
  msg.msg_iovlen = i;
788
789
0
  if (buf0 != NULL) {
790
0
    msg.msg_control = (caddr_t)&cmsgbuf.buf;
791
0
    msg.msg_controllen = sizeof(cmsgbuf.buf);
792
0
    cmsg = CMSG_FIRSTHDR(&msg);
793
0
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
794
0
    cmsg->cmsg_level = SOL_SOCKET;
795
0
    cmsg->cmsg_type = SCM_RIGHTS;
796
0
    *(int *)CMSG_DATA(cmsg) = buf0->fd;
797
0
  }
798
799
0
 again:
800
0
  if ((n = sendmsg(fd, &msg, 0)) == -1) {
801
0
    if (errno == EINTR)
802
0
      goto again;
803
0
    if (errno == EAGAIN || errno == ENOBUFS)
804
      /* lets retry later again */
805
0
      return (0);
806
0
    return (-1);
807
0
  }
808
809
  /*
810
   * assumption: fd got sent if sendmsg sent anything
811
   * this works because fds are passed one at a time
812
   */
813
0
  if (buf0 != NULL) {
814
0
    close(buf0->fd);
815
0
    buf0->fd = -1;
816
0
  }
817
818
0
  msgbuf_drain(msgbuf, n);
819
820
0
  return (0);
821
0
}
822
823
static int
824
ibuf_read_process(struct msgbuf *msgbuf, int fd)
825
0
{
826
0
  struct ibuf rbuf, msg;
827
0
  ssize_t sz;
828
829
0
  ibuf_from_buffer(&rbuf, msgbuf->rbuf, msgbuf->roff);
830
831
0
  do {
832
0
    if (msgbuf->rpmsg == NULL) {
833
0
      if (ibuf_size(&rbuf) < msgbuf->hdrsize)
834
0
        break;
835
      /* get size from header */
836
0
      ibuf_from_buffer(&msg, ibuf_data(&rbuf),
837
0
          msgbuf->hdrsize);
838
0
      if ((msgbuf->rpmsg = msgbuf->readhdr(&msg,
839
0
          msgbuf->rarg, &fd)) == NULL)
840
0
        goto fail;
841
0
    }
842
843
0
    if (ibuf_left(msgbuf->rpmsg) <= ibuf_size(&rbuf))
844
0
      sz = ibuf_left(msgbuf->rpmsg);
845
0
    else
846
0
      sz = ibuf_size(&rbuf);
847
848
    /* neither call below can fail */
849
0
    if (ibuf_get_ibuf(&rbuf, sz, &msg) == -1 ||
850
0
        ibuf_add_ibuf(msgbuf->rpmsg, &msg) == -1)
851
0
      goto fail;
852
853
0
    if (ibuf_left(msgbuf->rpmsg) == 0) {
854
0
      ibufq_push(&msgbuf->rbufs, msgbuf->rpmsg);
855
0
      msgbuf->rpmsg = NULL;
856
0
    }
857
0
  } while (ibuf_size(&rbuf) > 0);
858
859
0
  if (ibuf_size(&rbuf) > 0)
860
0
    memmove(msgbuf->rbuf, ibuf_data(&rbuf), ibuf_size(&rbuf));
861
0
  msgbuf->roff = ibuf_size(&rbuf);
862
863
0
  if (fd != -1)
864
0
    close(fd);
865
0
  return (1);
866
867
0
 fail:
868
  /* XXX how to properly clean up is unclear */
869
0
  if (fd != -1)
870
0
    close(fd);
871
0
  return (-1);
872
0
}
873
874
int
875
ibuf_read(int fd, struct msgbuf *msgbuf)
876
0
{
877
0
  struct iovec  iov;
878
0
  ssize_t   n;
879
880
0
  if (msgbuf->rbuf == NULL) {
881
0
    errno = EINVAL;
882
0
    return (-1);
883
0
  }
884
885
0
  iov.iov_base = msgbuf->rbuf + msgbuf->roff;
886
0
  iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
887
888
0
 again:
889
0
  if ((n = readv(fd, &iov, 1)) == -1) {
890
0
    if (errno == EINTR)
891
0
      goto again;
892
0
    if (errno == EAGAIN)
893
      /* lets retry later again */
894
0
      return (1);
895
0
    return (-1);
896
0
  }
897
0
  if (n == 0) /* connection closed */
898
0
    return (0);
899
900
0
  msgbuf->roff += n;
901
  /* new data arrived, try to process it */
902
0
  return (ibuf_read_process(msgbuf, -1));
903
0
}
904
905
int
906
msgbuf_read(int fd, struct msgbuf *msgbuf)
907
0
{
908
0
  struct msghdr    msg;
909
0
  struct cmsghdr    *cmsg;
910
0
  union {
911
0
    struct cmsghdr hdr;
912
0
    char  buf[CMSG_SPACE(sizeof(int) * 1)];
913
0
  } cmsgbuf;
914
0
  struct iovec     iov;
915
0
  ssize_t      n;
916
0
  int      fdpass = -1;
917
918
0
  if (msgbuf->rbuf == NULL) {
919
0
    errno = EINVAL;
920
0
    return (-1);
921
0
  }
922
923
0
  memset(&msg, 0, sizeof(msg));
924
0
  memset(&cmsgbuf, 0, sizeof(cmsgbuf));
925
926
0
  iov.iov_base = msgbuf->rbuf + msgbuf->roff;
927
0
  iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
928
0
  msg.msg_iov = &iov;
929
0
  msg.msg_iovlen = 1;
930
0
  msg.msg_control = &cmsgbuf.buf;
931
0
  msg.msg_controllen = sizeof(cmsgbuf.buf);
932
933
0
again:
934
0
  if ((n = recvmsg(fd, &msg, 0)) == -1) {
935
0
    if (errno == EINTR)
936
0
      goto again;
937
0
    if (errno == EMSGSIZE)
938
      /*
939
       * Not enough fd slots: fd passing failed, retry
940
       * to receive the message without fd.
941
       * imsg_get_fd() will return -1 in that case.
942
       */
943
0
      goto again;
944
0
    if (errno == EAGAIN)
945
      /* lets retry later again */
946
0
      return (1);
947
0
    return (-1);
948
0
  }
949
0
  if (n == 0) /* connection closed */
950
0
    return (0);
951
952
0
  msgbuf->roff += n;
953
954
0
  for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
955
0
      cmsg = CMSG_NXTHDR(&msg, cmsg)) {
956
0
    if (cmsg->cmsg_level == SOL_SOCKET &&
957
0
        cmsg->cmsg_type == SCM_RIGHTS) {
958
0
      int i, j, f;
959
960
      /*
961
       * We only accept one file descriptor.  Due to C
962
       * padding rules, our control buffer might contain
963
       * more than one fd, and we must close them.
964
       */
965
0
      j = ((char *)cmsg + cmsg->cmsg_len -
966
0
          (char *)CMSG_DATA(cmsg)) / sizeof(int);
967
0
      for (i = 0; i < j; i++) {
968
0
        f = ((int *)CMSG_DATA(cmsg))[i];
969
0
        if (i == 0)
970
0
          fdpass = f;
971
0
        else
972
0
          close(f);
973
0
      }
974
0
    }
975
    /* we do not handle other ctl data level */
976
0
  }
977
978
  /* new data arrived, try to process it */
979
0
  return (ibuf_read_process(msgbuf, fdpass));
980
0
}
981
982
static void
983
msgbuf_drain(struct msgbuf *msgbuf, size_t n)
984
0
{
985
0
  struct ibuf *buf;
986
987
0
  while ((buf = TAILQ_FIRST(&msgbuf->bufs.bufs)) != NULL) {
988
0
    if (n >= ibuf_size(buf)) {
989
0
      n -= ibuf_size(buf);
990
0
      TAILQ_REMOVE(&msgbuf->bufs.bufs, buf, entry);
991
0
      msgbuf->bufs.queued--;
992
0
      ibuf_free(buf);
993
0
    } else {
994
0
      buf->rpos += n;
995
0
      return;
996
0
    }
997
0
  }
998
0
}
999
1000
static void
1001
ibufq_init(struct ibufqueue *bufq)
1002
0
{
1003
0
  TAILQ_INIT(&bufq->bufs);
1004
0
  bufq->queued = 0;
1005
0
}
1006
1007
struct ibufqueue *
1008
ibufq_new(void)
1009
0
{
1010
0
  struct ibufqueue *bufq;
1011
1012
0
  if ((bufq = calloc(1, sizeof(*bufq))) == NULL)
1013
0
    return NULL;
1014
0
  ibufq_init(bufq);
1015
0
  return bufq;
1016
0
}
1017
1018
void
1019
ibufq_free(struct ibufqueue *bufq)
1020
0
{
1021
0
  if (bufq == NULL)
1022
0
    return;
1023
0
  ibufq_flush(bufq);
1024
0
  free(bufq);
1025
0
}
1026
1027
struct ibuf *
1028
ibufq_pop(struct ibufqueue *bufq)
1029
0
{
1030
0
  struct ibuf *buf;
1031
1032
0
  if ((buf = TAILQ_FIRST(&bufq->bufs)) == NULL)
1033
0
    return NULL;
1034
0
  TAILQ_REMOVE(&bufq->bufs, buf, entry);
1035
0
  bufq->queued--;
1036
0
  return buf;
1037
0
}
1038
1039
void
1040
ibufq_push(struct ibufqueue *bufq, struct ibuf *buf)
1041
0
{
1042
  /* if buf lives on the stack abort before causing more harm */
1043
0
  if (buf->fd == IBUF_FD_MARK_ON_STACK)
1044
0
    abort();
1045
0
  TAILQ_INSERT_TAIL(&bufq->bufs, buf, entry);
1046
0
  bufq->queued++;
1047
0
}
1048
1049
uint32_t
1050
ibufq_queuelen(struct ibufqueue *bufq)
1051
0
{
1052
0
  return (bufq->queued);
1053
0
}
1054
1055
void
1056
ibufq_concat(struct ibufqueue *to, struct ibufqueue *from)
1057
0
{
1058
0
  to->queued += from->queued;
1059
0
  TAILQ_CONCAT(&to->bufs, &from->bufs, entry);
1060
0
  from->queued = 0;
1061
0
}
1062
1063
void
1064
ibufq_flush(struct ibufqueue *bufq)
1065
0
{
1066
0
  struct ibuf *buf;
1067
1068
0
  while ((buf = TAILQ_FIRST(&bufq->bufs)) != NULL) {
1069
    TAILQ_REMOVE(&bufq->bufs, buf, entry);
1070
0
    ibuf_free(buf);
1071
0
  }
1072
0
  bufq->queued = 0;
1073
0
}