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