A cvsup file that pulls the "checked out" version of source. I'm referencing
[dragonfly.git] / sbin / rconfig / server.c
blob91288458447922cf736687c94f88cd3575456a5f
1 /*
2 * RCONFIG/SERVER.C
4 * $DragonFly: src/sbin/rconfig/server.c,v 1.1 2004/06/18 02:46:46 dillon Exp $
5 */
7 #include "defs.h"
9 static void server_connection(int fd);
10 static void service_packet_loop(int fd);
11 static void server_chld_exit(int signo);
12 static int nconnects;
14 void
15 doServer(void)
17 tag_t tag;
20 * Listen on one or more UDP and TCP addresses, fork for each one.
22 signal(SIGCHLD, SIG_IGN);
23 for (tag = AddrBase; tag; tag = tag->next) {
24 struct sockaddr_in sain;
25 char *host;
26 int lfd;
27 int fd;
28 int on = 1;
30 bzero(&sain, sizeof(sain));
31 if (tag->name == NULL) {
32 sain.sin_addr.s_addr = INADDR_ANY;
33 host = "<any>";
34 } else {
35 host = strdup(tag->name);
36 if (inet_aton(host, &sain.sin_addr) == 0) {
37 struct hostent *hp;
38 if ((hp = gethostbyname2(host, AF_INET)) == NULL) {
39 fprintf(stderr, "Unable to resolve %s\n", host);
40 exit(1);
42 bcopy(hp->h_addr_list[0], &sain.sin_addr, hp->h_length);
43 free(host);
44 host = strdup(hp->h_name);
45 endhostent();
48 sain.sin_port = htons(257);
49 sain.sin_len = sizeof(sain);
50 sain.sin_family = AF_INET;
51 fflush(stdout);
52 if (fork() == 0) {
53 if ((lfd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
54 fprintf(stderr, "%s: socket: %s\n", host, strerror(errno));
55 exit(1);
57 setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
58 if (bind(lfd, (void *)&sain, sizeof(sain)) < 0) {
59 fprintf(stderr, "%s: bind: %s\n", host, strerror(errno));
60 exit(1);
62 if (listen(lfd, 20) < 0) {
63 fprintf(stderr, "%s: listen: %s\n", host, strerror(errno));
64 exit(1);
66 signal(SIGCHLD, server_chld_exit);
67 for (;;) {
68 int slen = sizeof(sain);
69 fd = accept(lfd, (void *)&sain, &slen);
70 if (fd < 0) {
71 if (errno != EINTR)
72 break;
73 continue;
75 ++nconnects; /* XXX sigblock/sigsetmask */
76 if (fork() == 0) {
77 close(lfd);
78 server_connection(fd);
79 exit(0);
81 close(fd);
83 exit(0);
85 if (fork() == 0) {
86 if ((lfd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC)) < 0) {
87 fprintf(stderr, "%s: socket: %s\n", host, strerror(errno));
88 exit(1);
90 if (bind(lfd, (void *)&sain, sizeof(sain)) < 0) {
91 fprintf(stderr, "%s: bind: %s\n", host, strerror(errno));
92 exit(1);
94 service_packet_loop(lfd);
95 exit(1);
98 while (wait(NULL) > 0 || errno != EINTR)
102 static
103 void
104 server_chld_exit(int signo)
106 while (wait3(NULL, WNOHANG, NULL) > 0)
107 --nconnects;
110 static
111 void
112 server_connection(int fd)
114 FILE *fi;
115 FILE *fo;
116 char buf[256];
117 char *scan;
118 const char *cmd;
119 const char *name;
121 fi = fdopen(fd, "r");
122 fo = fdopen(dup(fd), "w");
124 if (gethostname(buf, sizeof(buf)) == 0) {
125 fprintf(fo, "108 HELLO SERVER=%s\r\n", buf);
126 } else {
127 fprintf(fo, "108 HELLO\r\n", buf);
129 fflush(fo);
131 while (fgets(buf, sizeof(buf), fi) != NULL) {
132 scan = buf;
133 cmd = parse_str(&scan, PAS_ALPHA);
134 if (cmd == NULL) {
135 fprintf(fo, "502 Illegal Command String\r\n");
136 } else if (strcasecmp(cmd, "VAR") == 0) {
137 fprintf(fo, "100 OK\r\n");
138 } else if (strcasecmp(cmd, "TAG") == 0) {
139 if ((name = parse_str(&scan, PAS_ALPHA|PAS_NUMERIC)) == NULL) {
140 fprintf(fo, "401 Illegal Tag\r\n");
141 } else {
142 char *path = NULL;
143 FILE *fp;
144 asprintf(&path, "%s/%s.sh", TagDir, name);
145 if ((fp = fopen(path, "r")) == NULL) {
146 fprintf(fo, "402 '%s' Not Found\r\n", name);
147 } else {
148 long bytes;
149 int n;
150 int error = 0;
152 fseek(fp, 0L, 2);
153 bytes = ftell(fp);
154 fseek(fp, 0L, 0);
155 fprintf(fo, "201 SIZE=%ld\r\n", bytes);
156 while (bytes > 0) {
157 n = (bytes > sizeof(buf)) ? sizeof(buf) : bytes;
158 n = fread(buf, 1, n, fp);
159 if (n <= 0) {
160 error = 1;
161 break;
163 if (fwrite(buf, 1, n, fo) != n) {
164 error = 1;
165 break;
167 bytes -= n;
169 fclose(fp);
170 if (bytes > 0 && ferror(fo) == 0) {
171 bzero(buf, sizeof(buf));
172 while (bytes > 0) {
173 n = (bytes > sizeof(buf)) ? sizeof(buf) : bytes;
174 if (fwrite(buf, 1, n, fo) != n)
175 break;
176 bytes -= n;
179 fprintf(fo, "202 ERROR=%d\r\n", error);
181 free(path);
183 } else if (strcasecmp(cmd, "IDLE") == 0) {
184 if ((name = parse_str(&scan, PAS_ANY)) == NULL) {
185 fprintf(fo, "401 Illegal String\r\n");
186 } else {
187 fprintf(fo, "109 %s\r\n", name);
189 } else if (strcasecmp(cmd, "QUIT") == 0) {
190 fprintf(fo, "409 Bye!\r\n");
191 break;
192 } else {
193 fprintf(fo, "501 Unknown Command\r\n");
195 fflush(fo);
197 fclose(fi);
198 fclose(fo);
202 * UDP packet loop. For now just handle one request per packet. Note that
203 * since the protocol is designed to be used in a broadcast environment,
204 * we only respond when we have something to contribute.
206 static
207 void
208 service_packet_loop(int fd)
210 struct sockaddr_in sain;
211 char ibuf[256+1];
212 char obuf[256+1];
213 int sain_len;
214 int n;
215 char *scan;
216 const char *cmd;
217 const char *name;
219 for (;;) {
220 sain_len = sizeof(sain);
221 n = recvfrom(fd, ibuf, sizeof(ibuf) - 1, 0, (void *)&sain, &sain_len);
222 if (n < 0) {
223 if (errno == EINTR)
224 continue;
225 break;
227 ibuf[n] = 0;
228 n = 0;
229 scan = ibuf;
230 cmd = parse_str(&scan, PAS_ALPHA);
231 if (cmd == NULL) {
233 } else if (strcasecmp(cmd, "TAG") == 0) {
234 if ((name = parse_str(&scan, PAS_ALPHA|PAS_NUMERIC)) != NULL) {
235 char *path = NULL;
236 struct stat st;
237 asprintf(&path, "%s/%s.sh", TagDir, name);
238 if (stat(path, &st) == 0) {
239 snprintf(obuf, sizeof(obuf), "101 TAG=%s\r\n", name);
240 n = strlen(obuf);
242 free(path);
245 if (n)
246 sendto(fd, obuf, n, 0, (void *)&sain, sain_len);