xref: /openbsd-src/usr.sbin/rpki-client/io.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: io.c,v 1.8 2019/11/29 05:09:50 benno 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 <openssl/x509.h>
29 
30 #include "extern.h"
31 
32 void
33 io_socket_blocking(int fd)
34 {
35 	int	 fl;
36 
37 	if ((fl = fcntl(fd, F_GETFL, 0)) == -1)
38 		err(1, "fcntl");
39 	if (fcntl(fd, F_SETFL, fl & ~O_NONBLOCK) == -1)
40 		err(1, "fcntl");
41 }
42 
43 void
44 io_socket_nonblocking(int fd)
45 {
46 	int	 fl;
47 
48 	if ((fl = fcntl(fd, F_GETFL, 0)) == -1)
49 		err(1, "fcntl");
50 	if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) == -1)
51 		err(1, "fcntl");
52 }
53 
54 /*
55  * Blocking write of a binary buffer.
56  * Buffers of length zero are simply ignored.
57  */
58 void
59 io_simple_write(int fd, const void *res, size_t sz)
60 {
61 	ssize_t	 ssz;
62 
63 	if (sz == 0)
64 		return;
65 	if ((ssz = write(fd, res, sz)) == -1)
66 		err(1, "write");
67 	else if ((size_t)ssz != sz)
68 		errx(1, "write: short write");
69 }
70 
71 /*
72  * Like io_simple_write() but into a buffer.
73  */
74 void
75 io_simple_buffer(char **b, size_t *bsz,
76 	size_t *bmax, const void *res, size_t sz)
77 {
78 
79 	if (*bsz + sz > *bmax) {
80 		if ((*b = realloc(*b, *bsz + sz)) == NULL)
81 			err(1, NULL);
82 		*bmax = *bsz + sz;
83 	}
84 
85 	memcpy(*b + *bsz, res, sz);
86 	*bsz += sz;
87 }
88 
89 /*
90  * Like io_buf_write() but into a buffer.
91  */
92 void
93 io_buf_buffer(char **b, size_t *bsz,
94 	size_t *bmax, const void *p, size_t sz)
95 {
96 
97 	io_simple_buffer(b, bsz, bmax, &sz, sizeof(size_t));
98 	if (sz > 0)
99 		io_simple_buffer(b, bsz, bmax, p, sz);
100 }
101 
102 /*
103  * Write a binary buffer of the given size, which may be zero.
104  */
105 void
106 io_buf_write(int fd, const void *p, size_t sz)
107 {
108 
109 	io_simple_write(fd, &sz, sizeof(size_t));
110 	io_simple_write(fd, p, sz);
111 }
112 
113 /*
114  * Like io_str_write() but into a buffer.
115  */
116 void
117 io_str_buffer(char **b, size_t *bsz, size_t *bmax, const char *p)
118 {
119 	size_t	 sz = (p == NULL) ? 0 : strlen(p);
120 
121 	io_buf_buffer(b, bsz, bmax, p, sz);
122 }
123 
124 /*
125  * Write a NUL-terminated string, which may be zero-length.
126  */
127 void
128 io_str_write(int fd, const char *p)
129 {
130 	size_t	 sz = (p == NULL) ? 0 : strlen(p);
131 
132 	io_buf_write(fd, p, sz);
133 }
134 
135 /*
136  * Read of a binary buffer that must be on a blocking descriptor.
137  * Does nothing if "sz" is zero.
138  * This will fail and exit on EOF.
139  */
140 void
141 io_simple_read(int fd, void *res, size_t sz)
142 {
143 	ssize_t	 ssz;
144 	char	*tmp;
145 
146 	tmp = res; /* arithmetic on a pointer to void is a GNU extension */
147 again:
148 	if (sz == 0)
149 		return;
150 	if ((ssz = read(fd, tmp, sz)) == -1)
151 		err(1, "read");
152 	else if (ssz == 0)
153 		errx(1, "read: unexpected end of file");
154 	else if ((size_t)ssz == sz)
155 		return;
156 	sz -= ssz;
157 	tmp += ssz;
158 	goto again;
159 }
160 
161 /*
162  * Read a binary buffer, allocating space for it.
163  * If the buffer is zero-sized, this won't allocate "res", but
164  * will still initialise it to NULL.
165  */
166 void
167 io_buf_read_alloc(int fd, void **res, size_t *sz)
168 {
169 
170 	*res = NULL;
171 	io_simple_read(fd, sz, sizeof(size_t));
172 	if (*sz == 0)
173 		return;
174 	if ((*res = malloc(*sz)) == NULL)
175 		err(1, NULL);
176 	io_simple_read(fd, *res, *sz);
177 }
178 
179 /*
180  * Read a string (which may just be \0 and zero-length), allocating
181  * space for it.
182  */
183 void
184 io_str_read(int fd, char **res)
185 {
186 	size_t	 sz;
187 
188 	io_simple_read(fd, &sz, sizeof(size_t));
189 	if ((*res = calloc(sz + 1, 1)) == NULL)
190 		err(1, NULL);
191 	io_simple_read(fd, *res, sz);
192 }
193