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