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