Coverage Report

Created: 2025-11-19 06:37

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