1 /* $OpenBSD: util.c,v 1.2 2020/01/17 20:45:50 bluhm Exp $ */ 2 3 /* 4 * Copyright (c) 2020 Alexander Bluhm <bluhm@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 22 #include <err.h> 23 #include <errno.h> 24 #include <netdb.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 #include "util.h" 31 32 void 33 task_enqueue(struct task *todo, int ch, const char *msg) 34 { 35 switch (ch) { 36 case 'E': 37 todo->t_type = TEOF; 38 todo->t_msg = NULL; 39 break; 40 case 'N': 41 todo->t_type = TDWN; 42 todo->t_msg = NULL; 43 break; 44 case 'r': 45 todo->t_type = TRCV; 46 todo->t_msg = msg; 47 break; 48 case 's': 49 todo->t_type = TSND; 50 todo->t_msg = msg; 51 break; 52 } 53 } 54 55 void 56 task_run(int s, struct task *todolist, size_t tlen) 57 { 58 size_t t; 59 60 for (t = 0; t < tlen; t++) { 61 switch(todolist[t].t_type) { 62 case TEOF: 63 receive_eof(s); 64 break; 65 case TDWN: 66 send_shutdown(s); 67 break; 68 case TRCV: 69 receive_line(s, todolist[t].t_msg); 70 break; 71 case TSND: 72 send_line(s, todolist[t].t_msg); 73 break; 74 } 75 } 76 } 77 78 void 79 alarm_timeout(void) 80 { 81 /* just abort after 10 seconds */ 82 if ((int)alarm(10) == -1) 83 err(1, "alarm"); 84 } 85 86 void 87 print_sockname(int s) 88 { 89 struct sockaddr_storage ss; 90 socklen_t slen; 91 char host[NI_MAXHOST], port[NI_MAXSERV]; 92 93 slen = sizeof(ss); 94 if (getsockname(s, (struct sockaddr *)&ss, &slen) == -1) 95 err(1, "getsockname"); 96 if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, sizeof(host), 97 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV)) 98 errx(1, "getnameinfo"); 99 printf("%s\n", port); 100 if (fflush(stdout) != 0) 101 err(1, "fflush stdout"); 102 fprintf(stderr, "sock: %s %s\n", host, port); 103 } 104 105 void 106 print_peername(int s) 107 { 108 struct sockaddr_storage ss; 109 socklen_t slen; 110 char host[NI_MAXHOST], port[NI_MAXSERV]; 111 112 slen = sizeof(ss); 113 if (getpeername(s, (struct sockaddr *)&ss, &slen) == -1) 114 err(1, "getpeername"); 115 if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, sizeof(host), 116 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV)) 117 errx(1, "getnameinfo"); 118 fprintf(stderr, "peer: %s %s\n", host, port); 119 } 120 121 void 122 receive_eof(int s) 123 { 124 char buf[100]; 125 size_t len; 126 ssize_t n; 127 128 n = recv(s, buf, sizeof(buf) - 1, 0); 129 if (n == -1) 130 err(1, "recv"); 131 if (n == 0) { 132 fprintf(stderr, "<<< EOF\n"); 133 return; 134 } 135 len = n; 136 buf[len] = '\0'; 137 if (buf[len - 1] == '\n') 138 buf[--len] = '\0'; 139 fprintf(stderr, "<<< %s\n", buf); 140 errx(1, "expected receive EOF, got '%s'", buf); 141 } 142 143 void 144 send_shutdown(int s) 145 { 146 if (shutdown(s, SHUT_WR) == -1) 147 err(1, "shutdown"); 148 } 149 150 void 151 receive_line(int s, const char *msg) 152 { 153 char buf[100]; 154 size_t off, len; 155 ssize_t n; 156 157 len = 0; 158 while (len < sizeof(buf) - 1) { 159 off = len; 160 n = recv(s, buf + off, sizeof(buf) - 1 - off, 0); 161 if (n == -1) 162 err(1, "recv"); 163 if (n == 0) { 164 fprintf(stderr, "<<< EOF\n"); 165 break; 166 } 167 len += n; 168 buf[len] = '\0'; 169 if (buf[len - 1] == '\n') 170 fprintf(stderr, "<<< %s", buf + off); 171 else 172 fprintf(stderr, "<<< %s\n", buf + off); 173 if (strchr(buf + off, '\n') != NULL) 174 break; 175 } 176 if (len == 0) 177 errx(1, "empty receive buffer"); 178 if (buf[len - 1] != '\n') 179 errx(1, "new line missing in receive buffer"); 180 buf[--len] = '\0'; 181 if (strcmp(msg, buf) != 0) 182 errx(1, "expected receive '%s', got '%s'", msg, buf); 183 } 184 185 void 186 send_line(int s, const char *msg) 187 { 188 char buf[100]; 189 size_t off, len; 190 ssize_t n; 191 192 len = strlcpy(buf, msg, sizeof(buf)); 193 if (len >= sizeof(buf)) 194 errx(1, "message too long for send buffer"); 195 if (buf[len] != '\n') { 196 buf[len++] = '\n'; 197 if (len >= sizeof(buf)) 198 errx(1, "new line too long for send buffer"); 199 buf[len] = 0; 200 } 201 202 off = 0; 203 while (off < len) { 204 fprintf(stderr, ">>> %s", buf + off); 205 n = send(s, buf + off, len - off, 0); 206 if (n == -1) 207 err(1, "send"); 208 off += n; 209 } 210 } 211