morse: use cos envelope and 8ms ramp time
[dragonfly.git] / sbin / rconfig / server.c
blob36fe6d90bc6e1a5469a3a7b5aa38c90ce24d127c
1 /*
2 * RCONFIG/SERVER.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:
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.
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.
36 * $DragonFly: src/sbin/rconfig/server.c,v 1.4 2006/10/20 14:50:42 pavalos Exp $
39 #include "defs.h"
41 static void server_connection(int fd);
42 static void service_packet_loop(int fd);
43 static void server_chld_exit(int signo);
44 static int nconnects;
46 void
47 doServer(void)
49 tag_t tag;
52 * Listen on one or more UDP and TCP addresses, fork for each one.
54 signal(SIGCHLD, SIG_IGN);
55 for (tag = AddrBase; tag; tag = tag->next) {
56 struct sockaddr_in sain;
57 const char *host;
58 int lfd;
59 int fd;
60 int on = 1;
62 bzero(&sain, sizeof(sain));
63 if (tag->name == NULL) {
64 sain.sin_addr.s_addr = INADDR_ANY;
65 host = "<any>";
66 } else {
67 if (inet_aton(tag->name, &sain.sin_addr) == 0) {
68 struct hostent *hp;
69 if ((hp = gethostbyname2(tag->name, AF_INET)) == NULL) {
70 fprintf(stderr, "Unable to resolve %s\n", tag->name);
71 exit(1);
73 bcopy(hp->h_addr_list[0], &sain.sin_addr, hp->h_length);
74 host = strdup(hp->h_name);
75 endhostent();
76 } else {
77 host = strdup(tag->name);
80 sain.sin_port = htons(257);
81 sain.sin_len = sizeof(sain);
82 sain.sin_family = AF_INET;
83 fflush(stdout);
84 if (fork() == 0) {
85 if ((lfd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
86 fprintf(stderr, "%s: socket: %s\n", host, strerror(errno));
87 exit(1);
89 setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
90 if (bind(lfd, (void *)&sain, sizeof(sain)) < 0) {
91 fprintf(stderr, "%s: bind: %s\n", host, strerror(errno));
92 exit(1);
94 if (listen(lfd, 20) < 0) {
95 fprintf(stderr, "%s: listen: %s\n", host, strerror(errno));
96 exit(1);
98 signal(SIGCHLD, server_chld_exit);
99 for (;;) {
100 int slen = sizeof(sain);
101 fd = accept(lfd, (void *)&sain, &slen);
102 if (fd < 0) {
103 if (errno != EINTR)
104 break;
105 continue;
107 ++nconnects; /* XXX sigblock/sigsetmask */
108 if (fork() == 0) {
109 close(lfd);
110 server_connection(fd);
111 exit(0);
113 close(fd);
115 exit(0);
117 if (fork() == 0) {
118 if ((lfd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC)) < 0) {
119 fprintf(stderr, "%s: socket: %s\n", host, strerror(errno));
120 exit(1);
122 if (bind(lfd, (void *)&sain, sizeof(sain)) < 0) {
123 fprintf(stderr, "%s: bind: %s\n", host, strerror(errno));
124 exit(1);
126 service_packet_loop(lfd);
127 exit(1);
130 while (wait(NULL) > 0 || errno != EINTR)
134 static
135 void
136 server_chld_exit(int signo __unused)
138 while (wait3(NULL, WNOHANG, NULL) > 0)
139 --nconnects;
142 static
143 void
144 server_connection(int fd)
146 FILE *fi;
147 FILE *fo;
148 char buf[256];
149 char *scan;
150 const char *cmd;
151 const char *name;
153 fi = fdopen(fd, "r");
154 fo = fdopen(dup(fd), "w");
156 if (gethostname(buf, sizeof(buf)) == 0) {
157 fprintf(fo, "108 HELLO SERVER=%s\r\n", buf);
158 } else {
159 fprintf(fo, "108 HELLO\r\n");
161 fflush(fo);
163 while (fgets(buf, sizeof(buf), fi) != NULL) {
164 scan = buf;
165 cmd = parse_str(&scan, PAS_ALPHA);
166 if (cmd == NULL) {
167 fprintf(fo, "502 Illegal Command String\r\n");
168 } else if (strcasecmp(cmd, "VAR") == 0) {
169 fprintf(fo, "100 OK\r\n");
170 } else if (strcasecmp(cmd, "TAG") == 0) {
171 if ((name = parse_str(&scan, PAS_ALPHA|PAS_NUMERIC)) == NULL) {
172 fprintf(fo, "401 Illegal Tag\r\n");
173 } else {
174 char *path = NULL;
175 FILE *fp;
176 asprintf(&path, "%s/%s.sh", TagDir, name);
177 if ((fp = fopen(path, "r")) == NULL) {
178 fprintf(fo, "402 '%s' Not Found\r\n", name);
179 } else {
180 size_t bytes;
181 size_t n;
182 int error = 0;
184 fseek(fp, 0L, 2);
185 bytes = (size_t)ftell(fp);
186 fseek(fp, 0L, 0);
187 fprintf(fo, "201 SIZE=%d\r\n", (int)bytes);
188 while (bytes > 0) {
189 n = (bytes > sizeof(buf)) ? sizeof(buf) : bytes;
190 n = fread(buf, 1, n, fp);
191 if (n <= 0) {
192 error = 1;
193 break;
195 if (fwrite(buf, 1, n, fo) != n) {
196 error = 1;
197 break;
199 bytes -= n;
201 fclose(fp);
202 if (bytes > 0 && ferror(fo) == 0) {
203 bzero(buf, sizeof(buf));
204 while (bytes > 0) {
205 n = (bytes > sizeof(buf)) ? sizeof(buf) : bytes;
206 if (fwrite(buf, 1, n, fo) != n)
207 break;
208 bytes -= n;
211 fprintf(fo, "202 ERROR=%d\r\n", error);
213 free(path);
215 } else if (strcasecmp(cmd, "IDLE") == 0) {
216 if ((name = parse_str(&scan, PAS_ANY)) == NULL) {
217 fprintf(fo, "401 Illegal String\r\n");
218 } else {
219 fprintf(fo, "109 %s\r\n", name);
221 } else if (strcasecmp(cmd, "QUIT") == 0) {
222 fprintf(fo, "409 Bye!\r\n");
223 break;
224 } else {
225 fprintf(fo, "501 Unknown Command\r\n");
227 fflush(fo);
229 fclose(fi);
230 fclose(fo);
234 * UDP packet loop. For now just handle one request per packet. Note that
235 * since the protocol is designed to be used in a broadcast environment,
236 * we only respond when we have something to contribute.
238 static
239 void
240 service_packet_loop(int fd)
242 struct sockaddr_in sain;
243 char ibuf[256+1];
244 char obuf[256+1];
245 int sain_len;
246 int n;
247 char *scan;
248 const char *cmd;
249 const char *name;
251 for (;;) {
252 sain_len = sizeof(sain);
253 n = recvfrom(fd, ibuf, sizeof(ibuf) - 1, 0, (void *)&sain, &sain_len);
254 if (n < 0) {
255 if (errno == EINTR)
256 continue;
257 break;
259 ibuf[n] = 0;
260 n = 0;
261 scan = ibuf;
262 cmd = parse_str(&scan, PAS_ALPHA);
263 if (cmd == NULL) {
265 } else if (strcasecmp(cmd, "TAG") == 0) {
266 if ((name = parse_str(&scan, PAS_ALPHA|PAS_NUMERIC)) != NULL) {
267 char *path = NULL;
268 struct stat st;
269 asprintf(&path, "%s/%s.sh", TagDir, name);
270 if (stat(path, &st) == 0) {
271 snprintf(obuf, sizeof(obuf), "101 TAG=%s\r\n", name);
272 n = strlen(obuf);
274 free(path);
277 if (n)
278 sendto(fd, obuf, n, 0, (void *)&sain, sain_len);