4 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
6 * This code is derived from software contributed to The DragonFly Project
7 * by Matthew Dillon <dillon@backplane.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
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
36 * $DragonFly: src/sbin/rconfig/server.c,v 1.3 2005/04/02 22:15:20 dillon Exp $
41 static void server_connection(int fd
);
42 static void service_packet_loop(int fd
);
43 static void server_chld_exit(int signo
);
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
;
62 bzero(&sain
, sizeof(sain
));
63 if (tag
->name
== NULL
) {
64 sain
.sin_addr
.s_addr
= INADDR_ANY
;
67 if (inet_aton(tag
->name
, &sain
.sin_addr
) == 0) {
69 if ((hp
= gethostbyname2(tag
->name
, AF_INET
)) == NULL
) {
70 fprintf(stderr
, "Unable to resolve %s\n", tag
->name
);
73 bcopy(hp
->h_addr_list
[0], &sain
.sin_addr
, hp
->h_length
);
74 host
= strdup(hp
->h_name
);
77 host
= strdup(tag
->name
);
80 sain
.sin_port
= htons(257);
81 sain
.sin_len
= sizeof(sain
);
82 sain
.sin_family
= AF_INET
;
85 if ((lfd
= socket(AF_INET
, SOCK_STREAM
, PF_UNSPEC
)) < 0) {
86 fprintf(stderr
, "%s: socket: %s\n", host
, strerror(errno
));
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
));
94 if (listen(lfd
, 20) < 0) {
95 fprintf(stderr
, "%s: listen: %s\n", host
, strerror(errno
));
98 signal(SIGCHLD
, server_chld_exit
);
100 int slen
= sizeof(sain
);
101 fd
= accept(lfd
, (void *)&sain
, &slen
);
107 ++nconnects
; /* XXX sigblock/sigsetmask */
110 server_connection(fd
);
118 if ((lfd
= socket(AF_INET
, SOCK_DGRAM
, PF_UNSPEC
)) < 0) {
119 fprintf(stderr
, "%s: socket: %s\n", host
, strerror(errno
));
122 if (bind(lfd
, (void *)&sain
, sizeof(sain
)) < 0) {
123 fprintf(stderr
, "%s: bind: %s\n", host
, strerror(errno
));
126 service_packet_loop(lfd
);
130 while (wait(NULL
) > 0 || errno
!= EINTR
)
136 server_chld_exit(int signo __unused
)
138 while (wait3(NULL
, WNOHANG
, NULL
) > 0)
144 server_connection(int fd
)
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
);
159 fprintf(fo
, "108 HELLO\r\n", buf
);
163 while (fgets(buf
, sizeof(buf
), fi
) != NULL
) {
165 cmd
= parse_str(&scan
, PAS_ALPHA
);
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");
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
);
185 bytes
= (size_t)ftell(fp
);
187 fprintf(fo
, "201 SIZE=%d\r\n", (int)bytes
);
189 n
= (bytes
> sizeof(buf
)) ? sizeof(buf
) : bytes
;
190 n
= fread(buf
, 1, n
, fp
);
195 if (fwrite(buf
, 1, n
, fo
) != n
) {
202 if (bytes
> 0 && ferror(fo
) == 0) {
203 bzero(buf
, sizeof(buf
));
205 n
= (bytes
> sizeof(buf
)) ? sizeof(buf
) : bytes
;
206 if (fwrite(buf
, 1, n
, fo
) != n
)
211 fprintf(fo
, "202 ERROR=%d\r\n", error
);
215 } else if (strcasecmp(cmd
, "IDLE") == 0) {
216 if ((name
= parse_str(&scan
, PAS_ANY
)) == NULL
) {
217 fprintf(fo
, "401 Illegal String\r\n");
219 fprintf(fo
, "109 %s\r\n", name
);
221 } else if (strcasecmp(cmd
, "QUIT") == 0) {
222 fprintf(fo
, "409 Bye!\r\n");
225 fprintf(fo
, "501 Unknown Command\r\n");
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.
240 service_packet_loop(int fd
)
242 struct sockaddr_in sain
;
252 sain_len
= sizeof(sain
);
253 n
= recvfrom(fd
, ibuf
, sizeof(ibuf
) - 1, 0, (void *)&sain
, &sain_len
);
262 cmd
= parse_str(&scan
, PAS_ALPHA
);
265 } else if (strcasecmp(cmd
, "TAG") == 0) {
266 if ((name
= parse_str(&scan
, PAS_ALPHA
|PAS_NUMERIC
)) != NULL
) {
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
);
278 sendto(fd
, obuf
, n
, 0, (void *)&sain
, sain_len
);