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