Home | History | Annotate | Line # | Download | only in altqd
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