altqd.c revision 1.6 1 /* $NetBSD: altqd.c,v 1.6 2001/08/22 08:52:35 itojun Exp $ */
2 /* $KAME: altqd.c,v 1.6 2001/08/20 08:25:23 kjc Exp $ */
3 /*
4 * Copyright (c) 2001 Theo de Raadt
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * Copyright (C) 1997-2000
28 * Sony Computer Science Laboratories, Inc. All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 *
39 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 * SUCH DAMAGE.
50 */
51
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <unistd.h>
55 #include <string.h>
56 #include <ctype.h>
57 #include <errno.h>
58 #include <signal.h>
59 #include <fcntl.h>
60 #include <syslog.h>
61 #include <err.h>
62
63 #include <sys/param.h>
64 #include <sys/socket.h>
65 #include <sys/un.h>
66 #include <sys/stat.h>
67
68 #include <net/if.h>
69 #include <netinet/in.h>
70 #include <arpa/inet.h>
71
72 #include <altq/altq.h>
73 #include "altq_qop.h"
74 #include "quip_server.h"
75
76 #define ALTQD_PID_FILE "/var/run/altqd.pid"
77 #define MAX_CLIENT 10
78
79 int altqd_socket = -1;
80 FILE * client[MAX_CLIENT];
81 int T; /* Current Thread number */
82 FILE *infp; /* Input file pointer */
83 char *infile = NULL; /* command input file. stdin if NULL. */
84 fd_set fds, t_fds;
85
86 #define DEFAULT_DEBUG_MASK 0
87 #define DEFAULT_LOGGING_LEVEL LOG_INFO
88
89 void usage(void);
90 void sig_pipe(int);
91 void sig_hup(int);
92 void sig_int(int);
93 void sig_term(int);
94
95 void
96 usage(void)
97 {
98 fprintf(stderr, "usage: altqd [-vd] [-f config]\n");
99 exit(1);
100 }
101
102 void
103 sig_pipe(int sig)
104 {
105 /*
106 * we have lost an API connection.
107 * a subsequent output operation will catch EPIPE.
108 */
109 }
110
111 int gotsig_hup, gotsig_int, gotsig_term;
112
113 void
114 sig_hup(int sig)
115 {
116 gotsig_hup = 1;
117 }
118
119 void
120 sig_int(int sig)
121 {
122 gotsig_int = 1;
123 }
124
125 void
126 sig_term(int sig)
127 {
128 gotsig_term = 1;
129 }
130
131 int
132 main(int argc, char **argv)
133 {
134 int c;
135 int i, maxfd;
136 extern char *optarg;
137
138 m_debug = DEFAULT_DEBUG_MASK;
139 l_debug = DEFAULT_LOGGING_LEVEL;
140
141 while ((c = getopt(argc, argv, "f:vDdl:")) != -1) {
142 switch (c) {
143 case 'f':
144 altqconfigfile = optarg;
145 break;
146 case 'D': /* -D => dummy mode */
147 Debug_mode = 1;
148 printf("Debug mode set.\n");
149 break;
150 case 'v':
151 l_debug = LOG_DEBUG;
152 m_debug |= DEBUG_ALTQ;
153 daemonize = 0;
154 break;
155 case 'd':
156 daemonize = 0;
157 break;
158 case 'l':
159 l_debug = atoi(optarg);
160 break;
161 default:
162 usage();
163 }
164 }
165
166 signal(SIGINT, sig_int);
167 signal(SIGTERM, sig_term);
168 signal(SIGHUP, sig_hup);
169 signal(SIGPIPE, sig_pipe);
170
171 if (daemonize)
172 openlog("altqd", LOG_PID, LOG_DAEMON);
173
174 if (qcmd_init() != 0) {
175 if (daemonize)
176 closelog();
177 exit(1);
178 }
179
180 /*
181 * open a unix domain socket for altqd clients
182 */
183 if ((altqd_socket = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
184 LOG(LOG_ERR, errno, "can't open unix domain socket");
185 else {
186 struct sockaddr_un addr;
187
188 bzero(&addr, sizeof(addr));
189 addr.sun_family = AF_LOCAL;
190 strlcpy(addr.sun_path, QUIP_PATH, sizeof(addr.sun_path));
191 unlink(QUIP_PATH);
192 if (bind(altqd_socket, (struct sockaddr *)&addr,
193 sizeof(addr)) < 0) {
194 LOG(LOG_ERR, errno, "can't bind to %s", QUIP_PATH);
195 close(altqd_socket);
196 altqd_socket = -1;
197 }
198 chmod(QUIP_PATH, 0666);
199 if (listen(altqd_socket, SOMAXCONN) < 0) {
200 LOG(LOG_ERR, errno, "can't listen to %s", QUIP_PATH);
201 close(altqd_socket);
202 altqd_socket = -1;
203 }
204 }
205
206 if (daemonize) {
207 FILE *fp;
208
209 daemon(0, 0);
210
211 /* save pid to the pid file (/var/tmp/altqd.pid) */
212 if ((fp = fopen(ALTQD_PID_FILE, "w")) != NULL) {
213 fprintf(fp, "%d\n", getpid());
214 fclose(fp);
215 } else
216 warn("can't open pid file: %s: %s",
217 ALTQD_PID_FILE, strerror(errno));
218 } else {
219 /* interactive mode */
220 if (infile) {
221 if ((infp = fopen(infile, "r")) == NULL) {
222 perror("Cannot open input file");
223 exit(1);
224 }
225 } else {
226 infp = stdin;
227 printf("\nEnter ? or command:\n");
228 printf("altqd %s> ", cur_ifname());
229 }
230 fflush(stdout);
231 }
232
233 /*
234 * go into the command mode.
235 * the code below is taken from rtap of rsvpd.
236 */
237 FD_ZERO(&fds);
238 maxfd = 0;
239 if (infp != NULL) {
240 FD_SET(fileno(infp), &fds);
241 maxfd = MAX(maxfd, fileno(infp) + 1);
242 }
243 if (altqd_socket >= 0) {
244 FD_SET(altqd_socket, &fds);
245 maxfd = MAX(maxfd, altqd_socket + 1);
246 }
247 while (1) {
248 int rc;
249
250 if (gotsig_hup) {
251 qcmd_destroyall();
252 gotsig_hup = 0;
253 printf("reinitializing altqd...\n");
254 qcmd_init();
255 }
256 if (gotsig_term) {
257 fprintf(stderr, "Exiting on signal %d\n", SIGTERM);
258
259 qcmd_destroyall();
260
261 /* if we have a pid file, remove it */
262 if (daemonize) {
263 unlink(ALTQD_PID_FILE);
264 closelog();
265 }
266 exit(0);
267 }
268 if (gotsig_int) {
269 fprintf(stderr, "Exiting on signal %d\n", SIGINT);
270 qcmd_destroyall();
271
272 /* if we have a pid file, remove it */
273 if (daemonize) {
274 unlink(ALTQD_PID_FILE);
275 closelog();
276 }
277 exit(0);
278 }
279
280 FD_COPY(&fds, &t_fds);
281 rc = select(maxfd, &t_fds, NULL, NULL, NULL);
282 if (rc < 0) {
283 if (errno != EINTR) {
284 perror("select");
285 exit(1);
286 }
287 continue;
288 }
289
290 /*
291 * If there is control input, read the input line,
292 * parse it, and execute.
293 */
294 if (infp && FD_ISSET(fileno(infp), &t_fds)) {
295 rc = DoCommand(infile, infp);
296 if (rc == 0) {
297 /*
298 * EOF on input. If reading from file,
299 * go to stdin; else exit.
300 */
301 if (infile) {
302 infp = stdin;
303 infile = NULL;
304 printf("\nEnter ? or command:\n");
305 FD_SET(fileno(infp), &fds);
306 } else {
307 LOG(LOG_INFO, 0, "Exiting.");
308 (void) qcmd_destroyall();
309 exit(0);
310 }
311 } else if (infp == stdin)
312 printf("altqd %s> ", cur_ifname());
313 fflush(stdout);
314 } else if (altqd_socket >= 0 && FD_ISSET(altqd_socket, &t_fds)) {
315 /*
316 * quip connection request from client via unix
317 * domain socket; get a new socket for this
318 * connection and add it to the select list.
319 */
320 int newsock = accept(altqd_socket, NULL, NULL);
321
322 if (newsock == -1) {
323 LOG(LOG_ERR, errno, "accept");
324 continue;
325 }
326 FD_SET(newsock, &fds);
327 for (i = 0; i < MAX_CLIENT; i++)
328 if (client[i] == NULL) {
329 client[i] = fdopen(newsock, "r+");
330 break;
331 }
332 maxfd = MAX(maxfd, newsock + 1);
333 } else {
334 /*
335 * check input from a client via unix domain socket
336 */
337 for (i = 0; i < MAX_CLIENT; i++) {
338 int fd;
339
340 if (client[i] == NULL)
341 continue;
342 fd = fileno(client[i]);
343 if (FD_ISSET(fd, &t_fds)) {
344 if (quip_input(client[i]) != 0 ||
345 fflush(client[i]) != 0) {
346 /* connection closed */
347 fclose(client[i]);
348 client[i] = NULL;
349 FD_CLR(fd, &fds);
350 }
351 }
352 }
353 }
354 }
355 }
356