4 * $DragonFly: src/sbin/rconfig/server.c,v 1.1 2004/06/18 02:46:46 dillon Exp $
9 static void server_connection(int fd
);
10 static void service_packet_loop(int fd
);
11 static void server_chld_exit(int signo
);
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
;
30 bzero(&sain
, sizeof(sain
));
31 if (tag
->name
== NULL
) {
32 sain
.sin_addr
.s_addr
= INADDR_ANY
;
35 host
= strdup(tag
->name
);
36 if (inet_aton(host
, &sain
.sin_addr
) == 0) {
38 if ((hp
= gethostbyname2(host
, AF_INET
)) == NULL
) {
39 fprintf(stderr
, "Unable to resolve %s\n", host
);
42 bcopy(hp
->h_addr_list
[0], &sain
.sin_addr
, hp
->h_length
);
44 host
= strdup(hp
->h_name
);
48 sain
.sin_port
= htons(257);
49 sain
.sin_len
= sizeof(sain
);
50 sain
.sin_family
= AF_INET
;
53 if ((lfd
= socket(AF_INET
, SOCK_STREAM
, PF_UNSPEC
)) < 0) {
54 fprintf(stderr
, "%s: socket: %s\n", host
, strerror(errno
));
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
));
62 if (listen(lfd
, 20) < 0) {
63 fprintf(stderr
, "%s: listen: %s\n", host
, strerror(errno
));
66 signal(SIGCHLD
, server_chld_exit
);
68 int slen
= sizeof(sain
);
69 fd
= accept(lfd
, (void *)&sain
, &slen
);
75 ++nconnects
; /* XXX sigblock/sigsetmask */
78 server_connection(fd
);
86 if ((lfd
= socket(AF_INET
, SOCK_DGRAM
, PF_UNSPEC
)) < 0) {
87 fprintf(stderr
, "%s: socket: %s\n", host
, strerror(errno
));
90 if (bind(lfd
, (void *)&sain
, sizeof(sain
)) < 0) {
91 fprintf(stderr
, "%s: bind: %s\n", host
, strerror(errno
));
94 service_packet_loop(lfd
);
98 while (wait(NULL
) > 0 || errno
!= EINTR
)
104 server_chld_exit(int signo
)
106 while (wait3(NULL
, WNOHANG
, NULL
) > 0)
112 server_connection(int fd
)
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
);
127 fprintf(fo
, "108 HELLO\r\n", buf
);
131 while (fgets(buf
, sizeof(buf
), fi
) != NULL
) {
133 cmd
= parse_str(&scan
, PAS_ALPHA
);
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");
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
);
155 fprintf(fo
, "201 SIZE=%ld\r\n", bytes
);
157 n
= (bytes
> sizeof(buf
)) ? sizeof(buf
) : bytes
;
158 n
= fread(buf
, 1, n
, fp
);
163 if (fwrite(buf
, 1, n
, fo
) != n
) {
170 if (bytes
> 0 && ferror(fo
) == 0) {
171 bzero(buf
, sizeof(buf
));
173 n
= (bytes
> sizeof(buf
)) ? sizeof(buf
) : bytes
;
174 if (fwrite(buf
, 1, n
, fo
) != n
)
179 fprintf(fo
, "202 ERROR=%d\r\n", error
);
183 } else if (strcasecmp(cmd
, "IDLE") == 0) {
184 if ((name
= parse_str(&scan
, PAS_ANY
)) == NULL
) {
185 fprintf(fo
, "401 Illegal String\r\n");
187 fprintf(fo
, "109 %s\r\n", name
);
189 } else if (strcasecmp(cmd
, "QUIT") == 0) {
190 fprintf(fo
, "409 Bye!\r\n");
193 fprintf(fo
, "501 Unknown Command\r\n");
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.
208 service_packet_loop(int fd
)
210 struct sockaddr_in sain
;
220 sain_len
= sizeof(sain
);
221 n
= recvfrom(fd
, ibuf
, sizeof(ibuf
) - 1, 0, (void *)&sain
, &sain_len
);
230 cmd
= parse_str(&scan
, PAS_ALPHA
);
233 } else if (strcasecmp(cmd
, "TAG") == 0) {
234 if ((name
= parse_str(&scan
, PAS_ALPHA
|PAS_NUMERIC
)) != NULL
) {
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
);
246 sendto(fd
, obuf
, n
, 0, (void *)&sain
, sain_len
);