186ed60a6SMatthew Dillon /*
286ed60a6SMatthew Dillon * RCONFIG/SERVER.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 server_connection(int fd);
4086ed60a6SMatthew Dillon static void service_packet_loop(int fd);
4186ed60a6SMatthew Dillon static void server_chld_exit(int signo);
4286ed60a6SMatthew Dillon static int nconnects;
4386ed60a6SMatthew Dillon
4486ed60a6SMatthew Dillon void
doServer(void)4586ed60a6SMatthew Dillon doServer(void)
4686ed60a6SMatthew Dillon {
4786ed60a6SMatthew Dillon tag_t tag;
4886ed60a6SMatthew Dillon
4986ed60a6SMatthew Dillon /*
5086ed60a6SMatthew Dillon * Listen on one or more UDP and TCP addresses, fork for each one.
5186ed60a6SMatthew Dillon */
5286ed60a6SMatthew Dillon signal(SIGCHLD, SIG_IGN);
5386ed60a6SMatthew Dillon for (tag = AddrBase; tag; tag = tag->next) {
5486ed60a6SMatthew Dillon struct sockaddr_in sain;
551213fdc4SMatthew Dillon const char *host;
5686ed60a6SMatthew Dillon int lfd;
5786ed60a6SMatthew Dillon int fd;
5886ed60a6SMatthew Dillon int on = 1;
5986ed60a6SMatthew Dillon
6086ed60a6SMatthew Dillon bzero(&sain, sizeof(sain));
6186ed60a6SMatthew Dillon if (tag->name == NULL) {
6286ed60a6SMatthew Dillon sain.sin_addr.s_addr = INADDR_ANY;
6386ed60a6SMatthew Dillon host = "<any>";
6486ed60a6SMatthew Dillon } else {
651213fdc4SMatthew Dillon if (inet_aton(tag->name, &sain.sin_addr) == 0) {
6686ed60a6SMatthew Dillon struct hostent *hp;
671213fdc4SMatthew Dillon if ((hp = gethostbyname2(tag->name, AF_INET)) == NULL) {
681213fdc4SMatthew Dillon fprintf(stderr, "Unable to resolve %s\n", tag->name);
6986ed60a6SMatthew Dillon exit(1);
7086ed60a6SMatthew Dillon }
7186ed60a6SMatthew Dillon bcopy(hp->h_addr_list[0], &sain.sin_addr, hp->h_length);
7286ed60a6SMatthew Dillon host = strdup(hp->h_name);
7386ed60a6SMatthew Dillon endhostent();
741213fdc4SMatthew Dillon } else {
751213fdc4SMatthew Dillon host = strdup(tag->name);
7686ed60a6SMatthew Dillon }
7786ed60a6SMatthew Dillon }
7886ed60a6SMatthew Dillon sain.sin_port = htons(257);
7986ed60a6SMatthew Dillon sain.sin_len = sizeof(sain);
8086ed60a6SMatthew Dillon sain.sin_family = AF_INET;
8186ed60a6SMatthew Dillon fflush(stdout);
8286ed60a6SMatthew Dillon if (fork() == 0) {
8386ed60a6SMatthew Dillon if ((lfd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
8486ed60a6SMatthew Dillon fprintf(stderr, "%s: socket: %s\n", host, strerror(errno));
8586ed60a6SMatthew Dillon exit(1);
8686ed60a6SMatthew Dillon }
8786ed60a6SMatthew Dillon setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
8886ed60a6SMatthew Dillon if (bind(lfd, (void *)&sain, sizeof(sain)) < 0) {
8986ed60a6SMatthew Dillon fprintf(stderr, "%s: bind: %s\n", host, strerror(errno));
9086ed60a6SMatthew Dillon exit(1);
9186ed60a6SMatthew Dillon }
9286ed60a6SMatthew Dillon if (listen(lfd, 20) < 0) {
9386ed60a6SMatthew Dillon fprintf(stderr, "%s: listen: %s\n", host, strerror(errno));
9486ed60a6SMatthew Dillon exit(1);
9586ed60a6SMatthew Dillon }
9686ed60a6SMatthew Dillon signal(SIGCHLD, server_chld_exit);
9786ed60a6SMatthew Dillon for (;;) {
98d70f9514SSascha Wildner socklen_t slen = sizeof(sain);
9986ed60a6SMatthew Dillon fd = accept(lfd, (void *)&sain, &slen);
10086ed60a6SMatthew Dillon if (fd < 0) {
10186ed60a6SMatthew Dillon if (errno != EINTR)
10286ed60a6SMatthew Dillon break;
10386ed60a6SMatthew Dillon continue;
10486ed60a6SMatthew Dillon }
10586ed60a6SMatthew Dillon ++nconnects; /* XXX sigblock/sigsetmask */
10686ed60a6SMatthew Dillon if (fork() == 0) {
10786ed60a6SMatthew Dillon close(lfd);
10886ed60a6SMatthew Dillon server_connection(fd);
10986ed60a6SMatthew Dillon exit(0);
11086ed60a6SMatthew Dillon }
11186ed60a6SMatthew Dillon close(fd);
11286ed60a6SMatthew Dillon }
11386ed60a6SMatthew Dillon exit(0);
11486ed60a6SMatthew Dillon }
11586ed60a6SMatthew Dillon if (fork() == 0) {
11686ed60a6SMatthew Dillon if ((lfd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC)) < 0) {
11786ed60a6SMatthew Dillon fprintf(stderr, "%s: socket: %s\n", host, strerror(errno));
11886ed60a6SMatthew Dillon exit(1);
11986ed60a6SMatthew Dillon }
12086ed60a6SMatthew Dillon if (bind(lfd, (void *)&sain, sizeof(sain)) < 0) {
12186ed60a6SMatthew Dillon fprintf(stderr, "%s: bind: %s\n", host, strerror(errno));
12286ed60a6SMatthew Dillon exit(1);
12386ed60a6SMatthew Dillon }
12486ed60a6SMatthew Dillon service_packet_loop(lfd);
12586ed60a6SMatthew Dillon exit(1);
12686ed60a6SMatthew Dillon }
12786ed60a6SMatthew Dillon }
12886ed60a6SMatthew Dillon while (wait(NULL) > 0 || errno != EINTR)
12986ed60a6SMatthew Dillon ;
13086ed60a6SMatthew Dillon }
13186ed60a6SMatthew Dillon
13286ed60a6SMatthew Dillon static
13386ed60a6SMatthew Dillon void
server_chld_exit(int signo __unused)1341213fdc4SMatthew Dillon server_chld_exit(int signo __unused)
13586ed60a6SMatthew Dillon {
13686ed60a6SMatthew Dillon while (wait3(NULL, WNOHANG, NULL) > 0)
13786ed60a6SMatthew Dillon --nconnects;
13886ed60a6SMatthew Dillon }
13986ed60a6SMatthew Dillon
14086ed60a6SMatthew Dillon static
14186ed60a6SMatthew Dillon void
server_connection(int fd)14286ed60a6SMatthew Dillon server_connection(int fd)
14386ed60a6SMatthew Dillon {
14486ed60a6SMatthew Dillon FILE *fi;
14586ed60a6SMatthew Dillon FILE *fo;
14686ed60a6SMatthew Dillon char buf[256];
14786ed60a6SMatthew Dillon char *scan;
14886ed60a6SMatthew Dillon const char *cmd;
14986ed60a6SMatthew Dillon const char *name;
15086ed60a6SMatthew Dillon
15186ed60a6SMatthew Dillon fi = fdopen(fd, "r");
15286ed60a6SMatthew Dillon fo = fdopen(dup(fd), "w");
15386ed60a6SMatthew Dillon
15486ed60a6SMatthew Dillon if (gethostname(buf, sizeof(buf)) == 0) {
15586ed60a6SMatthew Dillon fprintf(fo, "108 HELLO SERVER=%s\r\n", buf);
15686ed60a6SMatthew Dillon } else {
157a8b658efSPeter Avalos fprintf(fo, "108 HELLO\r\n");
15886ed60a6SMatthew Dillon }
15986ed60a6SMatthew Dillon fflush(fo);
16086ed60a6SMatthew Dillon
16186ed60a6SMatthew Dillon while (fgets(buf, sizeof(buf), fi) != NULL) {
16286ed60a6SMatthew Dillon scan = buf;
16386ed60a6SMatthew Dillon cmd = parse_str(&scan, PAS_ALPHA);
16486ed60a6SMatthew Dillon if (cmd == NULL) {
16586ed60a6SMatthew Dillon fprintf(fo, "502 Illegal Command String\r\n");
16686ed60a6SMatthew Dillon } else if (strcasecmp(cmd, "VAR") == 0) {
16786ed60a6SMatthew Dillon fprintf(fo, "100 OK\r\n");
16886ed60a6SMatthew Dillon } else if (strcasecmp(cmd, "TAG") == 0) {
169*063db479SAaron LI if ((name = parse_str(&scan, PAS_ALPHA|PAS_SYMBOL|PAS_NUMERIC))
170*063db479SAaron LI == NULL) {
17186ed60a6SMatthew Dillon fprintf(fo, "401 Illegal Tag\r\n");
17286ed60a6SMatthew Dillon } else {
17386ed60a6SMatthew Dillon char *path = NULL;
17486ed60a6SMatthew Dillon FILE *fp;
17586ed60a6SMatthew Dillon asprintf(&path, "%s/%s.sh", TagDir, name);
17686ed60a6SMatthew Dillon if ((fp = fopen(path, "r")) == NULL) {
17786ed60a6SMatthew Dillon fprintf(fo, "402 '%s' Not Found\r\n", name);
17886ed60a6SMatthew Dillon } else {
1791213fdc4SMatthew Dillon size_t bytes;
1801213fdc4SMatthew Dillon size_t n;
18186ed60a6SMatthew Dillon int error = 0;
18286ed60a6SMatthew Dillon
18386ed60a6SMatthew Dillon fseek(fp, 0L, 2);
1841213fdc4SMatthew Dillon bytes = (size_t)ftell(fp);
18586ed60a6SMatthew Dillon fseek(fp, 0L, 0);
1861213fdc4SMatthew Dillon fprintf(fo, "201 SIZE=%d\r\n", (int)bytes);
18786ed60a6SMatthew Dillon while (bytes > 0) {
18886ed60a6SMatthew Dillon n = (bytes > sizeof(buf)) ? sizeof(buf) : bytes;
18986ed60a6SMatthew Dillon n = fread(buf, 1, n, fp);
19086ed60a6SMatthew Dillon if (n <= 0) {
19186ed60a6SMatthew Dillon error = 1;
19286ed60a6SMatthew Dillon break;
19386ed60a6SMatthew Dillon }
19486ed60a6SMatthew Dillon if (fwrite(buf, 1, n, fo) != n) {
19586ed60a6SMatthew Dillon error = 1;
19686ed60a6SMatthew Dillon break;
19786ed60a6SMatthew Dillon }
19886ed60a6SMatthew Dillon bytes -= n;
19986ed60a6SMatthew Dillon }
20086ed60a6SMatthew Dillon fclose(fp);
20186ed60a6SMatthew Dillon if (bytes > 0 && ferror(fo) == 0) {
20286ed60a6SMatthew Dillon bzero(buf, sizeof(buf));
20386ed60a6SMatthew Dillon while (bytes > 0) {
20486ed60a6SMatthew Dillon n = (bytes > sizeof(buf)) ? sizeof(buf) : bytes;
20586ed60a6SMatthew Dillon if (fwrite(buf, 1, n, fo) != n)
20686ed60a6SMatthew Dillon break;
20786ed60a6SMatthew Dillon bytes -= n;
20886ed60a6SMatthew Dillon }
20986ed60a6SMatthew Dillon }
21086ed60a6SMatthew Dillon fprintf(fo, "202 ERROR=%d\r\n", error);
21186ed60a6SMatthew Dillon }
21286ed60a6SMatthew Dillon free(path);
21386ed60a6SMatthew Dillon }
21486ed60a6SMatthew Dillon } else if (strcasecmp(cmd, "IDLE") == 0) {
21586ed60a6SMatthew Dillon if ((name = parse_str(&scan, PAS_ANY)) == NULL) {
21686ed60a6SMatthew Dillon fprintf(fo, "401 Illegal String\r\n");
21786ed60a6SMatthew Dillon } else {
21886ed60a6SMatthew Dillon fprintf(fo, "109 %s\r\n", name);
21986ed60a6SMatthew Dillon }
22086ed60a6SMatthew Dillon } else if (strcasecmp(cmd, "QUIT") == 0) {
22186ed60a6SMatthew Dillon fprintf(fo, "409 Bye!\r\n");
22286ed60a6SMatthew Dillon break;
22386ed60a6SMatthew Dillon } else {
22486ed60a6SMatthew Dillon fprintf(fo, "501 Unknown Command\r\n");
22586ed60a6SMatthew Dillon }
22686ed60a6SMatthew Dillon fflush(fo);
22786ed60a6SMatthew Dillon }
22886ed60a6SMatthew Dillon fclose(fi);
22986ed60a6SMatthew Dillon fclose(fo);
23086ed60a6SMatthew Dillon }
23186ed60a6SMatthew Dillon
23286ed60a6SMatthew Dillon /*
23386ed60a6SMatthew Dillon * UDP packet loop. For now just handle one request per packet. Note that
23486ed60a6SMatthew Dillon * since the protocol is designed to be used in a broadcast environment,
23586ed60a6SMatthew Dillon * we only respond when we have something to contribute.
23686ed60a6SMatthew Dillon */
23786ed60a6SMatthew Dillon static
23886ed60a6SMatthew Dillon void
service_packet_loop(int fd)23986ed60a6SMatthew Dillon service_packet_loop(int fd)
24086ed60a6SMatthew Dillon {
24186ed60a6SMatthew Dillon struct sockaddr_in sain;
24286ed60a6SMatthew Dillon char ibuf[256+1];
24386ed60a6SMatthew Dillon char obuf[256+1];
244d70f9514SSascha Wildner socklen_t sain_len;
24586ed60a6SMatthew Dillon int n;
24686ed60a6SMatthew Dillon char *scan;
24786ed60a6SMatthew Dillon const char *cmd;
24886ed60a6SMatthew Dillon const char *name;
24986ed60a6SMatthew Dillon
25086ed60a6SMatthew Dillon for (;;) {
25186ed60a6SMatthew Dillon sain_len = sizeof(sain);
25286ed60a6SMatthew Dillon n = recvfrom(fd, ibuf, sizeof(ibuf) - 1, 0, (void *)&sain, &sain_len);
25386ed60a6SMatthew Dillon if (n < 0) {
25486ed60a6SMatthew Dillon if (errno == EINTR)
25586ed60a6SMatthew Dillon continue;
25686ed60a6SMatthew Dillon break;
25786ed60a6SMatthew Dillon }
25886ed60a6SMatthew Dillon ibuf[n] = 0;
25986ed60a6SMatthew Dillon n = 0;
26086ed60a6SMatthew Dillon scan = ibuf;
26186ed60a6SMatthew Dillon cmd = parse_str(&scan, PAS_ALPHA);
26286ed60a6SMatthew Dillon if (cmd == NULL) {
26386ed60a6SMatthew Dillon ;
26486ed60a6SMatthew Dillon } else if (strcasecmp(cmd, "TAG") == 0) {
265*063db479SAaron LI if ((name = parse_str(&scan, PAS_ALPHA|PAS_SYMBOL|PAS_NUMERIC))
266*063db479SAaron LI != NULL) {
26786ed60a6SMatthew Dillon char *path = NULL;
26886ed60a6SMatthew Dillon struct stat st;
26986ed60a6SMatthew Dillon asprintf(&path, "%s/%s.sh", TagDir, name);
27086ed60a6SMatthew Dillon if (stat(path, &st) == 0) {
27186ed60a6SMatthew Dillon snprintf(obuf, sizeof(obuf), "101 TAG=%s\r\n", name);
27286ed60a6SMatthew Dillon n = strlen(obuf);
27386ed60a6SMatthew Dillon }
27486ed60a6SMatthew Dillon free(path);
27586ed60a6SMatthew Dillon }
27686ed60a6SMatthew Dillon }
27786ed60a6SMatthew Dillon if (n)
27886ed60a6SMatthew Dillon sendto(fd, obuf, n, 0, (void *)&sain, sain_len);
27986ed60a6SMatthew Dillon }
28086ed60a6SMatthew Dillon }
28186ed60a6SMatthew Dillon
282