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