186ed60a6SMatthew Dillon /*
286ed60a6SMatthew Dillon * RCONFIG/SUBS.C
386ed60a6SMatthew Dillon *
47a25b4e0SMatthew Dillon * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
57a25b4e0SMatthew Dillon *
67a25b4e0SMatthew Dillon * This code is derived from software contributed to The DragonFly Project
77a25b4e0SMatthew Dillon * by Matthew Dillon <dillon@backplane.com>
87a25b4e0SMatthew Dillon *
97a25b4e0SMatthew Dillon * Redistribution and use in source and binary forms, with or without
107a25b4e0SMatthew Dillon * modification, are permitted provided that the following conditions
117a25b4e0SMatthew Dillon * are met:
127a25b4e0SMatthew Dillon *
137a25b4e0SMatthew Dillon * 1. Redistributions of source code must retain the above copyright
147a25b4e0SMatthew Dillon * notice, this list of conditions and the following disclaimer.
157a25b4e0SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
167a25b4e0SMatthew Dillon * notice, this list of conditions and the following disclaimer in
177a25b4e0SMatthew Dillon * the documentation and/or other materials provided with the
187a25b4e0SMatthew Dillon * distribution.
197a25b4e0SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its
207a25b4e0SMatthew Dillon * contributors may be used to endorse or promote products derived
217a25b4e0SMatthew Dillon * from this software without specific, prior written permission.
227a25b4e0SMatthew Dillon *
237a25b4e0SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
247a25b4e0SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
257a25b4e0SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
267a25b4e0SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
277a25b4e0SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
287a25b4e0SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
297a25b4e0SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
307a25b4e0SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
317a25b4e0SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
327a25b4e0SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
337a25b4e0SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
347a25b4e0SMatthew Dillon * SUCH DAMAGE.
3586ed60a6SMatthew Dillon */
3686ed60a6SMatthew Dillon
3786ed60a6SMatthew Dillon #include "defs.h"
3886ed60a6SMatthew Dillon
3986ed60a6SMatthew Dillon static void udp_alarm(int signo);
4086ed60a6SMatthew Dillon
4186ed60a6SMatthew Dillon static __inline
4286ed60a6SMatthew Dillon int
iswhite(char c)4386ed60a6SMatthew Dillon iswhite(char c)
4486ed60a6SMatthew Dillon {
4586ed60a6SMatthew Dillon return(c == ' ' || c == '\t' || c == '\r' || c == '\n');
4686ed60a6SMatthew Dillon }
4786ed60a6SMatthew Dillon
4886ed60a6SMatthew Dillon const char *
parse_str(char ** scanp,int flags)4986ed60a6SMatthew Dillon parse_str(char **scanp, int flags)
5086ed60a6SMatthew Dillon {
5186ed60a6SMatthew Dillon char *base;
5286ed60a6SMatthew Dillon char *ptr;
5386ed60a6SMatthew Dillon
5486ed60a6SMatthew Dillon for (base = *scanp; *base && iswhite(*base); ++base)
5586ed60a6SMatthew Dillon ;
5686ed60a6SMatthew Dillon for (ptr = base; *ptr && !iswhite(*ptr); ++ptr) {
5786ed60a6SMatthew Dillon if (flags & PAS_ALPHA) {
58*063db479SAaron LI if ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z'))
5986ed60a6SMatthew Dillon continue;
6086ed60a6SMatthew Dillon }
61*063db479SAaron LI if (flags & PAS_SYMBOL) {
62*063db479SAaron LI if (*ptr == '_' || *ptr == '.' || *ptr == '-' || *ptr == '+')
63*063db479SAaron LI continue;
6486ed60a6SMatthew Dillon }
6586ed60a6SMatthew Dillon if (flags & PAS_NUMERIC) {
6686ed60a6SMatthew Dillon if (*ptr >= '0' && *ptr <= '9')
6786ed60a6SMatthew Dillon continue;
6886ed60a6SMatthew Dillon }
6986ed60a6SMatthew Dillon if ((flags & PAS_ANY) == 0)
7086ed60a6SMatthew Dillon return(NULL);
7186ed60a6SMatthew Dillon }
7286ed60a6SMatthew Dillon if (*ptr)
7386ed60a6SMatthew Dillon *ptr++ = 0;
7486ed60a6SMatthew Dillon *scanp = ptr;
7586ed60a6SMatthew Dillon return(base);
7686ed60a6SMatthew Dillon }
7786ed60a6SMatthew Dillon
7886ed60a6SMatthew Dillon int
udp_transact(struct sockaddr_in * sain,struct sockaddr_in * rsin,int * pfd,char ** bufp,int * lenp,const char * ctl,...)7986ed60a6SMatthew Dillon udp_transact(struct sockaddr_in *sain, struct sockaddr_in *rsin, int *pfd,
8086ed60a6SMatthew Dillon char **bufp, int *lenp, const char *ctl, ...)
8186ed60a6SMatthew Dillon {
8286ed60a6SMatthew Dillon va_list va;
8386ed60a6SMatthew Dillon int fd;
8486ed60a6SMatthew Dillon int n;
85d70f9514SSascha Wildner socklen_t rsin_len = sizeof(*rsin);
8686ed60a6SMatthew Dillon int rc;
8786ed60a6SMatthew Dillon int nretry = 3;
8886ed60a6SMatthew Dillon int timeout = 1;
8986ed60a6SMatthew Dillon int on = 1;
9086ed60a6SMatthew Dillon char buf[2048];
9186ed60a6SMatthew Dillon
9286ed60a6SMatthew Dillon if (*bufp) {
9386ed60a6SMatthew Dillon free(*bufp);
9486ed60a6SMatthew Dillon *bufp = NULL;
9586ed60a6SMatthew Dillon *lenp = 0;
9686ed60a6SMatthew Dillon }
9786ed60a6SMatthew Dillon if ((fd = *pfd) < 0) {
9886ed60a6SMatthew Dillon struct sockaddr_in lsin;
9986ed60a6SMatthew Dillon
10086ed60a6SMatthew Dillon lsin.sin_addr.s_addr = INADDR_ANY;
10186ed60a6SMatthew Dillon lsin.sin_port = 0;
10286ed60a6SMatthew Dillon lsin.sin_family = AF_INET;
10386ed60a6SMatthew Dillon if ((fd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC)) < 0) {
10486ed60a6SMatthew Dillon asprintf(bufp, "udp_transaction: socket: %s", strerror(errno));
10586ed60a6SMatthew Dillon *lenp = strlen(*bufp);
10686ed60a6SMatthew Dillon return(509);
10786ed60a6SMatthew Dillon }
10886ed60a6SMatthew Dillon setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
10986ed60a6SMatthew Dillon if (bind(fd, (void *)&lsin, sizeof(lsin)) < 0) {
11086ed60a6SMatthew Dillon asprintf(bufp, "udp_transaction: bind: %s", strerror(errno));
11186ed60a6SMatthew Dillon *lenp = strlen(*bufp);
11286ed60a6SMatthew Dillon close(fd);
11386ed60a6SMatthew Dillon return(509);
11486ed60a6SMatthew Dillon }
11586ed60a6SMatthew Dillon *pfd = fd;
11686ed60a6SMatthew Dillon }
117be853a16SMatthew Dillon retry:
11886ed60a6SMatthew Dillon va_start(va, ctl);
11986ed60a6SMatthew Dillon vsnprintf(buf, sizeof(buf), ctl, va);
12086ed60a6SMatthew Dillon va_end(va);
12186ed60a6SMatthew Dillon if (sendto(fd, buf, strlen(buf), 0, (void *)sain, sizeof(*sain)) >= 0) {
12286ed60a6SMatthew Dillon struct sigaction nact;
12386ed60a6SMatthew Dillon struct sigaction oact;
12486ed60a6SMatthew Dillon
12586ed60a6SMatthew Dillon bzero(&nact, sizeof(nact));
12686ed60a6SMatthew Dillon nact.sa_handler = udp_alarm;
12786ed60a6SMatthew Dillon nact.sa_flags = 0;
12886ed60a6SMatthew Dillon sigaction(SIGALRM, &nact, &oact);
12986ed60a6SMatthew Dillon alarm(timeout);
13086ed60a6SMatthew Dillon n = recvfrom(fd, buf, sizeof(buf) - 1, 0, (void *)rsin, &rsin_len);
13186ed60a6SMatthew Dillon alarm(0);
13286ed60a6SMatthew Dillon sigaction(SIGALRM, &oact, NULL);
133be853a16SMatthew Dillon if (n < 0) {
134be853a16SMatthew Dillon if (errno == EINTR && --nretry > 0)
13586ed60a6SMatthew Dillon goto retry;
13686ed60a6SMatthew Dillon asprintf(bufp, "udp_transaction: recvfrom: timeout");
13786ed60a6SMatthew Dillon *lenp = strlen(*bufp);
13886ed60a6SMatthew Dillon return(508);
13986ed60a6SMatthew Dillon }
14086ed60a6SMatthew Dillon while (n > 0 && (buf[n - 1] == '\r' || buf[n - 1] == '\n'))
14186ed60a6SMatthew Dillon --n;
14286ed60a6SMatthew Dillon buf[n] = 0;
143be853a16SMatthew Dillon rc = strtol(buf, NULL, 10);
14486ed60a6SMatthew Dillon *bufp = strdup(buf);
14586ed60a6SMatthew Dillon *lenp = strlen(buf);
14686ed60a6SMatthew Dillon } else {
14786ed60a6SMatthew Dillon rc = 508;
14886ed60a6SMatthew Dillon asprintf(bufp, "udp_transaction: sendto: %s", strerror(errno));
14986ed60a6SMatthew Dillon *lenp = strlen(*bufp);
15086ed60a6SMatthew Dillon }
15186ed60a6SMatthew Dillon return(rc);
15286ed60a6SMatthew Dillon }
15386ed60a6SMatthew Dillon
15486ed60a6SMatthew Dillon int
tcp_transact(struct sockaddr_in * sain,FILE ** pfi,FILE ** pfo,char ** bufp,int * lenp,const char * ctl,...)15586ed60a6SMatthew Dillon tcp_transact(struct sockaddr_in *sain, FILE **pfi, FILE **pfo, char **bufp,
15686ed60a6SMatthew Dillon int *lenp, const char *ctl, ...)
15786ed60a6SMatthew Dillon {
15886ed60a6SMatthew Dillon char buf[2048];
15986ed60a6SMatthew Dillon va_list va;
16086ed60a6SMatthew Dillon int rc;
16186ed60a6SMatthew Dillon int n;
16286ed60a6SMatthew Dillon
16386ed60a6SMatthew Dillon if (*bufp) {
16486ed60a6SMatthew Dillon free(*bufp);
16586ed60a6SMatthew Dillon *bufp = NULL;
16686ed60a6SMatthew Dillon }
16786ed60a6SMatthew Dillon if (*pfi == NULL) {
16886ed60a6SMatthew Dillon int fd;
16986ed60a6SMatthew Dillon
17086ed60a6SMatthew Dillon if ((fd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
17186ed60a6SMatthew Dillon asprintf(bufp, "tcp_transaction: socket: %s", strerror(errno));
17286ed60a6SMatthew Dillon *lenp = strlen(*bufp);
17386ed60a6SMatthew Dillon return(509);
17486ed60a6SMatthew Dillon }
17586ed60a6SMatthew Dillon if (connect(fd, (void *)sain, sizeof(*sain)) < 0) {
17686ed60a6SMatthew Dillon asprintf(bufp, "tcp_transaction: connect: %s", strerror(errno));
17786ed60a6SMatthew Dillon *lenp = strlen(*bufp);
17886ed60a6SMatthew Dillon close(fd);
17986ed60a6SMatthew Dillon return(509);
18086ed60a6SMatthew Dillon }
18186ed60a6SMatthew Dillon *pfi = fdopen(fd, "r");
18286ed60a6SMatthew Dillon *pfo = fdopen(dup(fd), "w");
18386ed60a6SMatthew Dillon if (tcp_transact(sain, pfi, pfo, bufp, lenp, NULL) != 108) {
18486ed60a6SMatthew Dillon fclose(*pfi);
18586ed60a6SMatthew Dillon fclose(*pfo);
18686ed60a6SMatthew Dillon *pfi = *pfo = NULL;
18786ed60a6SMatthew Dillon if (*bufp)
18886ed60a6SMatthew Dillon free(*bufp);
18986ed60a6SMatthew Dillon asprintf(bufp, "tcp_transaction: did not get HELLO from server\n");
19086ed60a6SMatthew Dillon *lenp = strlen(*bufp);
19186ed60a6SMatthew Dillon return(509);
19286ed60a6SMatthew Dillon }
19386ed60a6SMatthew Dillon if (*bufp) {
19486ed60a6SMatthew Dillon printf("%s\n", *bufp);
19586ed60a6SMatthew Dillon free(*bufp);
19686ed60a6SMatthew Dillon *bufp = NULL;
19786ed60a6SMatthew Dillon }
19886ed60a6SMatthew Dillon }
19986ed60a6SMatthew Dillon if (ctl) {
20086ed60a6SMatthew Dillon va_start(va, ctl);
20186ed60a6SMatthew Dillon vfprintf(*pfo, ctl, va);
20286ed60a6SMatthew Dillon va_end(va);
20386ed60a6SMatthew Dillon fflush(*pfo);
20486ed60a6SMatthew Dillon }
20586ed60a6SMatthew Dillon if (fgets(buf, sizeof(buf), *pfi) != NULL) {
20686ed60a6SMatthew Dillon rc = strtol(buf, NULL, 10);
20786ed60a6SMatthew Dillon n = strlen(buf);
20886ed60a6SMatthew Dillon if (rc == 201 && strstr(buf, "SIZE=") != NULL) {
20986ed60a6SMatthew Dillon *lenp = strtol(strstr(buf, "SIZE=") + 5, NULL, 0);
21086ed60a6SMatthew Dillon if (*lenp > 0)
21186ed60a6SMatthew Dillon *bufp = malloc(*lenp);
21286ed60a6SMatthew Dillon for (rc = 0; *bufp && rc < *lenp; rc += n) {
2131213fdc4SMatthew Dillon if ((n = *lenp - rc) > (int)sizeof(buf))
21486ed60a6SMatthew Dillon n = sizeof(buf);
21586ed60a6SMatthew Dillon n = fread(*bufp + rc, 1, n, *pfi);
21686ed60a6SMatthew Dillon if (n <= 0)
21786ed60a6SMatthew Dillon break;
21886ed60a6SMatthew Dillon }
21986ed60a6SMatthew Dillon if (rc == *lenp && fgets(buf, sizeof(buf), *pfi)) {
22086ed60a6SMatthew Dillon if (strstr(buf, "ERROR=")) {
22186ed60a6SMatthew Dillon rc = strtol(strstr(buf, "ERROR=") + 6, NULL, 0);
22286ed60a6SMatthew Dillon if (rc == 0)
22386ed60a6SMatthew Dillon rc = 201;
22486ed60a6SMatthew Dillon else
22586ed60a6SMatthew Dillon rc = 509;
22686ed60a6SMatthew Dillon } else {
22786ed60a6SMatthew Dillon rc = 509;
22886ed60a6SMatthew Dillon }
22986ed60a6SMatthew Dillon } else {
23086ed60a6SMatthew Dillon rc = 509;
23186ed60a6SMatthew Dillon }
23286ed60a6SMatthew Dillon if (rc != 201) {
23386ed60a6SMatthew Dillon free(*bufp);
23486ed60a6SMatthew Dillon asprintf(bufp, "tcp_transaction: download failed\n");
23586ed60a6SMatthew Dillon *lenp = strlen(*bufp);
23686ed60a6SMatthew Dillon }
23786ed60a6SMatthew Dillon } else {
23886ed60a6SMatthew Dillon while (n > 0 && (buf[n-1] == '\r' || buf[n-1] == '\n'))
23986ed60a6SMatthew Dillon --n;
24086ed60a6SMatthew Dillon buf[n] = 0;
24186ed60a6SMatthew Dillon *bufp = strdup(buf);
24286ed60a6SMatthew Dillon *lenp = n;
24386ed60a6SMatthew Dillon }
24486ed60a6SMatthew Dillon } else {
24586ed60a6SMatthew Dillon asprintf(bufp, "tcp_transaction: read: %s", strerror(errno));
24686ed60a6SMatthew Dillon *lenp = strlen(*bufp);
24786ed60a6SMatthew Dillon fclose(*pfi);
24886ed60a6SMatthew Dillon fclose(*pfo);
24986ed60a6SMatthew Dillon *pfi = *pfo = NULL;
25086ed60a6SMatthew Dillon rc = 509;
25186ed60a6SMatthew Dillon }
25286ed60a6SMatthew Dillon return(rc);
25386ed60a6SMatthew Dillon }
25486ed60a6SMatthew Dillon
25586ed60a6SMatthew Dillon static
25686ed60a6SMatthew Dillon void
udp_alarm(int signo __unused)2571213fdc4SMatthew Dillon udp_alarm(int signo __unused)
25886ed60a6SMatthew Dillon {
25986ed60a6SMatthew Dillon /* do nothing */
26086ed60a6SMatthew Dillon }
26186ed60a6SMatthew Dillon
262