xref: /openbsd/usr.sbin/rpki-client/io.c (revision 274d7c50)
1 /*	$OpenBSD: io.c,v 1.5 2019/08/13 13:34:43 florian 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(EXIT_FAILURE, "fcntl");
39 	if (fcntl(fd, F_SETFL, fl & ~O_NONBLOCK) == -1)
40 		err(EXIT_FAILURE, "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(EXIT_FAILURE, "fcntl");
50 	if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) == -1)
51 		err(EXIT_FAILURE, "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(EXIT_FAILURE, "write");
67 	else if ((size_t)ssz != sz)
68 		errx(EXIT_FAILURE, "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(EXIT_FAILURE, 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 
145 again:
146 	if (sz == 0)
147 		return;
148 	if ((ssz = read(fd, res, sz)) == -1)
149 		err(EXIT_FAILURE, "read");
150 	else if (ssz == 0)
151 		errx(EXIT_FAILURE, "read: unexpected end of file");
152 	else if ((size_t)ssz == sz)
153 		return;
154 	sz -= ssz;
155 	res += 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(EXIT_FAILURE, 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(EXIT_FAILURE, NULL);
189 	io_simple_read(fd, *res, sz);
190 }
191