xref: /openbsd-src/usr.sbin/rpki-client/io.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /*	$OpenBSD: io.c,v 1.9 2020/09/12 15:46:48 claudio Exp $ */
2 /*
3  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/queue.h>
19 
20 #include <assert.h>
21 #include <err.h>
22 #include <fcntl.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include "extern.h"
29 
30 void
31 io_socket_blocking(int fd)
32 {
33 	int	 fl;
34 
35 	if ((fl = fcntl(fd, F_GETFL, 0)) == -1)
36 		err(1, "fcntl");
37 	if (fcntl(fd, F_SETFL, fl & ~O_NONBLOCK) == -1)
38 		err(1, "fcntl");
39 }
40 
41 void
42 io_socket_nonblocking(int fd)
43 {
44 	int	 fl;
45 
46 	if ((fl = fcntl(fd, F_GETFL, 0)) == -1)
47 		err(1, "fcntl");
48 	if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) == -1)
49 		err(1, "fcntl");
50 }
51 
52 /*
53  * Blocking write of a binary buffer.
54  * Buffers of length zero are simply ignored.
55  */
56 void
57 io_simple_write(int fd, const void *res, size_t sz)
58 {
59 	ssize_t	 ssz;
60 
61 	if (sz == 0)
62 		return;
63 	if ((ssz = write(fd, res, sz)) == -1)
64 		err(1, "write");
65 	else if ((size_t)ssz != sz)
66 		errx(1, "write: short write");
67 }
68 
69 /*
70  * Like io_simple_write() but into a buffer.
71  */
72 void
73 io_simple_buffer(char **b, size_t *bsz,
74 	size_t *bmax, const void *res, size_t sz)
75 {
76 
77 	if (*bsz + sz > *bmax) {
78 		if ((*b = realloc(*b, *bsz + sz)) == NULL)
79 			err(1, NULL);
80 		*bmax = *bsz + sz;
81 	}
82 
83 	memcpy(*b + *bsz, res, sz);
84 	*bsz += sz;
85 }
86 
87 /*
88  * Like io_buf_write() but into a buffer.
89  */
90 void
91 io_buf_buffer(char **b, size_t *bsz,
92 	size_t *bmax, const void *p, size_t sz)
93 {
94 
95 	io_simple_buffer(b, bsz, bmax, &sz, sizeof(size_t));
96 	if (sz > 0)
97 		io_simple_buffer(b, bsz, bmax, p, sz);
98 }
99 
100 /*
101  * Write a binary buffer of the given size, which may be zero.
102  */
103 void
104 io_buf_write(int fd, const void *p, size_t sz)
105 {
106 
107 	io_simple_write(fd, &sz, sizeof(size_t));
108 	io_simple_write(fd, p, sz);
109 }
110 
111 /*
112  * Like io_str_write() but into a buffer.
113  */
114 void
115 io_str_buffer(char **b, size_t *bsz, size_t *bmax, const char *p)
116 {
117 	size_t	 sz = (p == NULL) ? 0 : strlen(p);
118 
119 	io_buf_buffer(b, bsz, bmax, p, sz);
120 }
121 
122 /*
123  * Write a NUL-terminated string, which may be zero-length.
124  */
125 void
126 io_str_write(int fd, const char *p)
127 {
128 	size_t	 sz = (p == NULL) ? 0 : strlen(p);
129 
130 	io_buf_write(fd, p, sz);
131 }
132 
133 /*
134  * Read of a binary buffer that must be on a blocking descriptor.
135  * Does nothing if "sz" is zero.
136  * This will fail and exit on EOF.
137  */
138 void
139 io_simple_read(int fd, void *res, size_t sz)
140 {
141 	ssize_t	 ssz;
142 	char	*tmp;
143 
144 	tmp = res; /* arithmetic on a pointer to void is a GNU extension */
145 again:
146 	if (sz == 0)
147 		return;
148 	if ((ssz = read(fd, tmp, sz)) == -1)
149 		err(1, "read");
150 	else if (ssz == 0)
151 		errx(1, "read: unexpected end of file");
152 	else if ((size_t)ssz == sz)
153 		return;
154 	sz -= ssz;
155 	tmp += ssz;
156 	goto again;
157 }
158 
159 /*
160  * Read a binary buffer, allocating space for it.
161  * If the buffer is zero-sized, this won't allocate "res", but
162  * will still initialise it to NULL.
163  */
164 void
165 io_buf_read_alloc(int fd, void **res, size_t *sz)
166 {
167 
168 	*res = NULL;
169 	io_simple_read(fd, sz, sizeof(size_t));
170 	if (*sz == 0)
171 		return;
172 	if ((*res = malloc(*sz)) == NULL)
173 		err(1, NULL);
174 	io_simple_read(fd, *res, *sz);
175 }
176 
177 /*
178  * Read a string (which may just be \0 and zero-length), allocating
179  * space for it.
180  */
181 void
182 io_str_read(int fd, char **res)
183 {
184 	size_t	 sz;
185 
186 	io_simple_read(fd, &sz, sizeof(size_t));
187 	if ((*res = calloc(sz + 1, 1)) == NULL)
188 		err(1, NULL);
189 	io_simple_read(fd, *res, sz);
190 }
191