1 /* 2 * RCONFIG/SUBS.C 3 * 4 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. 5 * 6 * This code is derived from software contributed to The DragonFly Project 7 * by Matthew Dillon <dillon@backplane.com> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 3. Neither the name of The DragonFly Project nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific, prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include "defs.h" 38 39 static void udp_alarm(int signo); 40 41 static __inline 42 int 43 iswhite(char c) 44 { 45 return(c == ' ' || c == '\t' || c == '\r' || c == '\n'); 46 } 47 48 const char * 49 parse_str(char **scanp, int flags) 50 { 51 char *base; 52 char *ptr; 53 54 for (base = *scanp; *base && iswhite(*base); ++base) 55 ; 56 for (ptr = base; *ptr && !iswhite(*ptr); ++ptr) { 57 if (flags & PAS_ALPHA) { 58 if ((*ptr >= 'a' && *ptr <= 'z') || 59 (*ptr >= 'A' && *ptr <= 'Z') || 60 *ptr == '_' 61 ) { 62 continue; 63 } 64 } 65 if (flags & PAS_NUMERIC) { 66 if (*ptr >= '0' && *ptr <= '9') 67 continue; 68 } 69 if ((flags & PAS_ANY) == 0) 70 return(NULL); 71 } 72 if (*ptr) 73 *ptr++ = 0; 74 *scanp = ptr; 75 return(base); 76 } 77 78 int 79 udp_transact(struct sockaddr_in *sain, struct sockaddr_in *rsin, int *pfd, 80 char **bufp, int *lenp, const char *ctl, ...) 81 { 82 va_list va; 83 int fd; 84 int n; 85 socklen_t rsin_len = sizeof(*rsin); 86 int rc; 87 int nretry = 3; 88 int timeout = 1; 89 int on = 1; 90 char buf[2048]; 91 92 if (*bufp) { 93 free(*bufp); 94 *bufp = NULL; 95 *lenp = 0; 96 } 97 if ((fd = *pfd) < 0) { 98 struct sockaddr_in lsin; 99 100 lsin.sin_addr.s_addr = INADDR_ANY; 101 lsin.sin_port = 0; 102 lsin.sin_family = AF_INET; 103 if ((fd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC)) < 0) { 104 asprintf(bufp, "udp_transaction: socket: %s", strerror(errno)); 105 *lenp = strlen(*bufp); 106 return(509); 107 } 108 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); 109 if (bind(fd, (void *)&lsin, sizeof(lsin)) < 0) { 110 asprintf(bufp, "udp_transaction: bind: %s", strerror(errno)); 111 *lenp = strlen(*bufp); 112 close(fd); 113 return(509); 114 } 115 *pfd = fd; 116 } 117 retry: 118 va_start(va, ctl); 119 vsnprintf(buf, sizeof(buf), ctl, va); 120 va_end(va); 121 if (sendto(fd, buf, strlen(buf), 0, (void *)sain, sizeof(*sain)) >= 0) { 122 struct sigaction nact; 123 struct sigaction oact; 124 125 bzero(&nact, sizeof(nact)); 126 nact.sa_handler = udp_alarm; 127 nact.sa_flags = 0; 128 sigaction(SIGALRM, &nact, &oact); 129 alarm(timeout); 130 n = recvfrom(fd, buf, sizeof(buf) - 1, 0, (void *)rsin, &rsin_len); 131 alarm(0); 132 sigaction(SIGALRM, &oact, NULL); 133 if (n < 0) { 134 if (errno == EINTR && --nretry > 0) 135 goto retry; 136 asprintf(bufp, "udp_transaction: recvfrom: timeout"); 137 *lenp = strlen(*bufp); 138 return(508); 139 } 140 while (n > 0 && (buf[n - 1] == '\r' || buf[n - 1] == '\n')) 141 --n; 142 buf[n] = 0; 143 rc = strtol(buf, NULL, 10); 144 *bufp = strdup(buf); 145 *lenp = strlen(buf); 146 } else { 147 rc = 508; 148 asprintf(bufp, "udp_transaction: sendto: %s", strerror(errno)); 149 *lenp = strlen(*bufp); 150 } 151 return(rc); 152 } 153 154 int 155 tcp_transact(struct sockaddr_in *sain, FILE **pfi, FILE **pfo, char **bufp, 156 int *lenp, const char *ctl, ...) 157 { 158 char buf[2048]; 159 va_list va; 160 int rc; 161 int n; 162 163 if (*bufp) { 164 free(*bufp); 165 *bufp = NULL; 166 } 167 if (*pfi == NULL) { 168 int fd; 169 170 if ((fd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { 171 asprintf(bufp, "tcp_transaction: socket: %s", strerror(errno)); 172 *lenp = strlen(*bufp); 173 return(509); 174 } 175 if (connect(fd, (void *)sain, sizeof(*sain)) < 0) { 176 asprintf(bufp, "tcp_transaction: connect: %s", strerror(errno)); 177 *lenp = strlen(*bufp); 178 close(fd); 179 return(509); 180 } 181 *pfi = fdopen(fd, "r"); 182 *pfo = fdopen(dup(fd), "w"); 183 if (tcp_transact(sain, pfi, pfo, bufp, lenp, NULL) != 108) { 184 fclose(*pfi); 185 fclose(*pfo); 186 *pfi = *pfo = NULL; 187 if (*bufp) 188 free(*bufp); 189 asprintf(bufp, "tcp_transaction: did not get HELLO from server\n"); 190 *lenp = strlen(*bufp); 191 return(509); 192 } 193 if (*bufp) { 194 printf("%s\n", *bufp); 195 free(*bufp); 196 *bufp = NULL; 197 } 198 } 199 if (ctl) { 200 va_start(va, ctl); 201 vfprintf(*pfo, ctl, va); 202 va_end(va); 203 fflush(*pfo); 204 } 205 if (fgets(buf, sizeof(buf), *pfi) != NULL) { 206 rc = strtol(buf, NULL, 10); 207 n = strlen(buf); 208 if (rc == 201 && strstr(buf, "SIZE=") != NULL) { 209 *lenp = strtol(strstr(buf, "SIZE=") + 5, NULL, 0); 210 if (*lenp > 0) 211 *bufp = malloc(*lenp); 212 for (rc = 0; *bufp && rc < *lenp; rc += n) { 213 if ((n = *lenp - rc) > (int)sizeof(buf)) 214 n = sizeof(buf); 215 n = fread(*bufp + rc, 1, n, *pfi); 216 if (n <= 0) 217 break; 218 } 219 if (rc == *lenp && fgets(buf, sizeof(buf), *pfi)) { 220 if (strstr(buf, "ERROR=")) { 221 rc = strtol(strstr(buf, "ERROR=") + 6, NULL, 0); 222 if (rc == 0) 223 rc = 201; 224 else 225 rc = 509; 226 } else { 227 rc = 509; 228 } 229 } else { 230 rc = 509; 231 } 232 if (rc != 201) { 233 free(*bufp); 234 asprintf(bufp, "tcp_transaction: download failed\n"); 235 *lenp = strlen(*bufp); 236 } 237 } else { 238 while (n > 0 && (buf[n-1] == '\r' || buf[n-1] == '\n')) 239 --n; 240 buf[n] = 0; 241 *bufp = strdup(buf); 242 *lenp = n; 243 } 244 } else { 245 asprintf(bufp, "tcp_transaction: read: %s", strerror(errno)); 246 *lenp = strlen(*bufp); 247 fclose(*pfi); 248 fclose(*pfo); 249 *pfi = *pfo = NULL; 250 rc = 509; 251 } 252 return(rc); 253 } 254 255 static 256 void 257 udp_alarm(int signo __unused) 258 { 259 /* do nothing */ 260 } 261 262