1 /* $OpenBSD: util.c,v 1.3 2021/07/06 11:50:34 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 print_sockname(int s) 80 { 81 struct sockaddr_storage ss; 82 socklen_t slen; 83 char host[NI_MAXHOST], port[NI_MAXSERV]; 84 85 slen = sizeof(ss); 86 if (getsockname(s, (struct sockaddr *)&ss, &slen) == -1) 87 err(1, "getsockname"); 88 if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, sizeof(host), 89 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV)) 90 errx(1, "getnameinfo"); 91 printf("%s\n", port); 92 if (fflush(stdout) != 0) 93 err(1, "fflush stdout"); 94 fprintf(stderr, "sock: %s %s\n", host, port); 95 } 96 97 void 98 print_peername(int s) 99 { 100 struct sockaddr_storage ss; 101 socklen_t slen; 102 char host[NI_MAXHOST], port[NI_MAXSERV]; 103 104 slen = sizeof(ss); 105 if (getpeername(s, (struct sockaddr *)&ss, &slen) == -1) 106 err(1, "getpeername"); 107 if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, sizeof(host), 108 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV)) 109 errx(1, "getnameinfo"); 110 fprintf(stderr, "peer: %s %s\n", host, port); 111 } 112 113 void 114 receive_eof(int s) 115 { 116 char buf[100]; 117 size_t len; 118 ssize_t n; 119 120 n = recv(s, buf, sizeof(buf) - 1, 0); 121 if (n == -1) 122 err(1, "recv"); 123 if (n == 0) { 124 fprintf(stderr, "<<< EOF\n"); 125 return; 126 } 127 len = n; 128 buf[len] = '\0'; 129 if (buf[len - 1] == '\n') 130 buf[--len] = '\0'; 131 fprintf(stderr, "<<< %s\n", buf); 132 errx(1, "expected receive EOF, got '%s'", buf); 133 } 134 135 void 136 send_shutdown(int s) 137 { 138 if (shutdown(s, SHUT_WR) == -1) 139 err(1, "shutdown"); 140 } 141 142 void 143 receive_line(int s, const char *msg) 144 { 145 char buf[100]; 146 size_t off, len; 147 ssize_t n; 148 149 len = 0; 150 while (len < sizeof(buf) - 1) { 151 off = len; 152 n = recv(s, buf + off, sizeof(buf) - 1 - off, 0); 153 if (n == -1) 154 err(1, "recv"); 155 if (n == 0) { 156 fprintf(stderr, "<<< EOF\n"); 157 break; 158 } 159 len += n; 160 buf[len] = '\0'; 161 if (buf[len - 1] == '\n') 162 fprintf(stderr, "<<< %s", buf + off); 163 else 164 fprintf(stderr, "<<< %s\n", buf + off); 165 if (strchr(buf + off, '\n') != NULL) 166 break; 167 } 168 if (len == 0) 169 errx(1, "empty receive buffer"); 170 if (buf[len - 1] != '\n') 171 errx(1, "new line missing in receive buffer"); 172 buf[--len] = '\0'; 173 if (strcmp(msg, buf) != 0) 174 errx(1, "expected receive '%s', got '%s'", msg, buf); 175 } 176 177 void 178 send_line(int s, const char *msg) 179 { 180 char buf[100]; 181 size_t off, len; 182 ssize_t n; 183 184 len = strlcpy(buf, msg, sizeof(buf)); 185 if (len >= sizeof(buf)) 186 errx(1, "message too long for send buffer"); 187 if (buf[len] != '\n') { 188 buf[len++] = '\n'; 189 if (len >= sizeof(buf)) 190 errx(1, "new line too long for send buffer"); 191 buf[len] = 0; 192 } 193 194 off = 0; 195 while (off < len) { 196 fprintf(stderr, ">>> %s", buf + off); 197 n = send(s, buf + off, len - off, 0); 198 if (n == -1) 199 err(1, "send"); 200 off += n; 201 } 202 } 203