Exemple #1
0
/* allocate */
tpool_t *tpool_create(unsigned int cnt, tfunc controller, tfunc handler)
{
	tpool_t *tp = malloc(sizeof *tp);

	/* set it up */
	if (tp)
		tpool_init(tp, cnt, controller, handler);

	return tp;
}
int main(void)
{
    int i;
    tpool_t test_pool;

    tpool_init(&test_pool, 8, 20);

    for ( i = 0; i < 5; i++) {
        tpool_add_work(test_pool, job, str[i]);
    }

    tpool_destroy(test_pool, 1);

    return 0;
}
Exemple #3
0
int main()
{
	tpool_t *t;
	char buf[256], *ptr;
	int len, i = 0;

#    ifdef DEBUG
	log_open("stderr", "tp_test", -1);
#    endif

	t = tpool_init(NULL, 3, 2, 2);

	printf("Thread Pool[%d] initlized OK, try to write your message after >\n", getpid());
	printf("Main thread: %p\n", pthread_self());
	do
	{
		printf(">");
		fflush(stdout);

		if (!fgets(buf, sizeof(buf) - 1, stdin))
		{
			puts("Aborted!\n");
			break;
		}
		if (buf[0] == '\r' || buf[0] == '\n')
			continue;
		len = strlen(buf);
		buf[len - 1] = '\0';
		if (!strcasecmp(buf, "quit") || !strcasecmp(buf, "exit"))
		{
			puts("Quit!\n");
			break;
		}
		else if (!strcasecmp(buf, "cancel"))
		{
			for (i = 0; i < t->max_total; i++)
			{
				int cc;

				if (!(t->threads[i].status & TPOOL_THREAD_ACTIVED))
					continue;
				pthread_cancel(t->threads[i].tid);
			}
			continue;
		}
		else if (!strcasecmp(buf, "cancel2"))
		{
			tpool_cancel(t);
			tpool_destroy(t);
			exit(0);
		}
		else if (!strcasecmp(buf, "timeout"))
		{
			tpool_cancel_timeout(t, 5);
			continue;
		}
		else if (!strcasecmp(buf, "display"))
		{
			ptr = tpool_draw(t);
			puts(ptr);
			free(ptr);
			continue;
		}
		ptr = strdup(buf);
		printf("strdup(%p)\n", ptr);
		tpool_exec(t, test_task, test_cancel, ptr);
	}
	while (1);

	//tpool_cancel(t);
	tpool_destroy(t);
	exit(0);
}
Exemple #4
0
int
main(int argc, char **argv)
{
	int             debug = 0, conftest = 0, nodaemon = 0;
	int             i = 0;
	unsigned int    clilen;
	struct sockaddr_in cliaddr;
	struct timeval  start, end;
	char           *cnfg = DEF_CNFG;
	char		localhost[MAXNAMLEN + 1], path[MAXNAMLEN + 1];
	FILE           *pidfp;
	octet_t         oct;
	ruleset_t      *rs;

	/*
	 * Who am I running as ? 
	 */

	uname(&myname);

	/*
	 * spocp_err = 0 ;
	 */

	memset(&srv, 0, sizeof(srv_t));

	pthread_mutex_init(&(srv.mutex), NULL);
	pthread_mutex_init(&(srv.mlock), NULL);

	gethostname(localhost, MAXNAMLEN);
#ifdef HAVE_GETDOMAINNAME
	getdomainname(path, MAXNAMLEN);
#else
	{
		char *pos;
		if(pos = strstr(localhost, ".")) strncpy(path, pos+1, MAXNAMLEN);
		else strcpy(path, "");
	}
#endif

	if (0)
		printf("Domain: %s\n", path);

	srv.hostname = Strdup(localhost);

	/*
	 * truncating input strings to reasonable length
	 */
	for (i = 0; i < argc; i++)
		if (strlen(argv[i]) > 512)
			argv[i][512] = '\0';

	while ((i = getopt(argc, argv, "Dhrtf:d:")) != EOF) {
		switch (i) {

		case 'D':
			nodaemon = 1;
			break;

		case 'f':
			cnfg = Strdup(optarg);
			break;

		case 'd':
			debug = atoi(optarg);
			if (debug < 0)
				debug = 0;
			break;

		case 't':
			conftest = 1;
			break;

		case 'r':
			srv.readonly = 1;

		case 'h':
		default:
			fprintf(stderr, "Usage: %s [-t] ", argv[0]);
			fprintf(stderr, "[-f configfile] ");
			fprintf(stderr, "[-D] [-d debuglevel]\n");
			exit(0);
		}
	}

	srv.root = ruleset_new(0);

	if (srv_init(&srv, cnfg) < 0)
		exit(1);

	if (srv.port && srv.uds) {
		fprintf(stderr,
			"Sorry are not allowed to listen on both a unix domain socket and a port\n");
		exit(1);
	}

	if (srv.logfile)
		spocp_open_log(srv.logfile, debug);
	else if (debug)
		spocp_open_log(0, debug);

	if (srv.name){
		localcontext = (char *) Calloc(strlen(srv.name) + strlen("//") + 1,
				       sizeof(char));

		/* Flawfinder: ignore */
		sprintf(localcontext, "//%s", srv.name);		
	}
	else {
		localcontext = (char *) Calloc(strlen(localhost) + strlen("//") + 1,
				       sizeof(char));

		/* Flawfinder: ignore */
		sprintf(localcontext, "//%s", localhost);
	}

	/*
	 * where I put the access rules for access to this server and its
	 * rules 
	 */
	snprintf(path, MAXNAMLEN, "%s/server", localcontext);
	oct_assign(&oct, path);
	if ((rs = ruleset_create(&oct, srv.root)) == 0)
		exit(1);

	rs->db = db_new();

	/*
	 * access rules for operations 
	 */
	snprintf(path, MAXNAMLEN, "%s/operation", localcontext);
	oct_assign(&oct, path);
	if ((rs = ruleset_create(&oct, srv.root)) == 0)
		exit(1);

	rs->db = db_new();


	LOG(SPOCP_INFO) {
		traceLog(LOG_INFO, "Local context: \"%s\"", localcontext);
		traceLog(LOG_INFO, "initializing backends");
		if (srv.root->db)
			plugin_display(srv.plugin);
	}

	if (srv.plugin) {
		run_plugin_init(&srv);
	}

	if ( get_rules( &srv ) != SPOCP_SUCCESS ) 
		exit(1);

	/*ruleset_tree( srv.root, 0);*/

	/* If only testing configuration and rulefile this is as far as I go */
	if (conftest) {
		traceLog(LOG_INFO,"Configuration was OK");
		exit(0);
	}

	gettimeofday(&start, NULL);

	if (srv.port || srv.uds) {

		/*
		 * stdin and stdout will not be used from here on, close to
		 * save file descriptors 
		 */

		fclose(stdin);
		fclose(stdout);

#ifdef HAVE_SSL
		/*
		 * ---------------------------------------------------------- 
		 */
		/*
		 * build our SSL context, whether it will ever be used or not 
		 */

		/*
		 * mutex'es for openSSL to use 
		 */
		THREAD_setup();

		if (srv.certificateFile && srv.privateKey && srv.caList) {
			traceLog(LOG_INFO,"Initializing the TLS/SSL environment");
			if (!(srv.ctx = tls_init(&srv))) {
				return FALSE;
			}
		}

		/*
		 * ---------------------------------------------------------- 
		 */
#endif

#ifdef HAVE_SASL
		{
			int             r = sasl_server_init(sasl_cb, "spocp");
			if (r != SASL_OK) {
				traceLog( LOG_ERR,
				    "Unable to initialized SASL library: %s",
				     sasl_errstring(r, NULL, NULL));
				return FALSE;
			}
		}
#endif

		saci_init();
		if( nodaemon == 0 ) { 
#ifdef HAVE_DAEMON
			if (daemon(1, 1) < 0) {
				fprintf(stderr, "couldn't go daemon\n");
				exit(1);
			}
#else
			daemon_init("spocp", 0);
#endif
		}

		if (srv.pidfile) {
			/*
			 * Write the PID file. 
			 */
			pidfp = fopen(srv.pidfile, "w");

			if (pidfp == (FILE *) 0) {
				fprintf(stderr,
					"Couldn't open pidfile \"%s\"\n",
					srv.pidfile);
				exit(1);
			}
			fprintf(pidfp, "%d\n", (int) getpid());
			fclose(pidfp);
		}

		if (srv.port) {
			LOG(SPOCP_INFO) traceLog( LOG_INFO,
				"Asked to listen on port %d", srv.port);

			if ((srv.listen_fd =
			     spocp_stream_socket(srv.port)) < 0)
				exit(1);

			srv.id = (char *) Malloc(16);
			sprintf(srv.id, "spocp-%d", srv.port);

			srv.type = AF_INET;
		} else {
			LOG(SPOCP_INFO)
			    traceLog(LOG_INFO,"Asked to listen on unix domain socket");
			if ((srv.listen_fd =
			     spocp_unix_domain_socket(srv.uds)) < 0)
				exit(1);

			srv.id = (char *) Malloc(7 + strlen(srv.uds));
			/* Flawfinder: ignore */
			sprintf(srv.id, "spocp-%s", srv.uds);

			srv.type = AF_UNIX;
		}

		xsignal(SIGCHLD, sig_chld);
		xsignal(SIGPIPE, sig_pipe);
		xsignal(SIGINT, sig_int);
		xsignal(SIGTERM, sig_term);
		xsignal(SIGUSR1, sig_usr1);

		clilen = sizeof(cliaddr);

		DEBUG(SPOCP_DSRV) traceLog(LOG_DEBUG,"Creating threads");
		/*
		 * returns the pool the threads are picking work from 
		 */
		srv.work = tpool_init(srv.threads, 64, 1);

		spocp_srv_run(&srv);

	} else {
		conn_t         *conn;

		saci_init();
		DEBUG(SPOCP_DSRV) traceLog(LOG_DEBUG,"---->");

		LOG(SPOCP_INFO) traceLog(LOG_INFO,"Reading STDIN");

		/*
		 * If I want to use this I have to do init_server() first
		 * conn = spocp_open_connection( STDIN_FILENO, &srv ) ; 
		 */
		/*
		 * this is much simpler 
		 */
		conn = conn_new();
		conn_setup(conn, &srv, STDIN_FILENO, "localhost", "127.0.0.1");

		LOG(SPOCP_INFO) traceLog(LOG_INFO,"Running server");

		spocp_server((void *) conn);

		gettimeofday(&end, NULL);

		print_elapsed("query time:", start, end);

		conn_free( conn );
	}

	srv_free( &srv );
	if (cnfg != DEF_CNFG)
		Free( cnfg );

	exit(0);
}
Exemple #5
0
int main(int argc, char *argv[])
{
	 
	    tpool_t *pool;  
	  
	    
	    logmy=log_open("test.log", 0);
		
	   
	    pool=tpool_init(10,20,1);

		
		socket_branch();

		char  Construction[2];
   
    while(1)
     	{

		
         

			
		 	printf("Please Input Construction number On Server:\t"); 
		 	scanf("%s", Construction); 
			printf("%s\n", Construction);
			
            switch (Construction[1]) {
            

            case 9:
                	tpool_destroy(pool,1);
					log_close(logmy);
					pthread_exit(NULL);
					exit (EXIT_SUCCESS);

            case 8:
                    exit (EXIT_FAILURE);
					
		    case 6:
                    break;

            default:
                    break;
            }
    			 

		
         struct sockaddr_in client_addr;
		 int client_addr_length =sizeof(client_addr);

 		 int new_server_socket_fd =accept(server_socket_fd,(struct sockaddr*)&client_addr, &client_addr_length);
		 if(new_server_socket_fd < 0)
		 	{
				perror("Server Accept Failed:");
				break;
		    }
		 else
		 	{   

                printf("Accept Client Socket Address\n");
				char peeraddrstr[60];
			    char peerip[18];
			    
			    time_t timep;
				time(&timep);

				
				int len = sizeof(client_addr);
				if(!getpeername(new_server_socket_fd, (struct sockaddr *)&client_addr, &len))
				 {
					 sprintf(peeraddrstr, "time: %s\npeer address: %s:%d\n\n",ctime(&timep) , inet_ntop(AF_INET, &client_addr.sin_addr, peerip, sizeof(peerip)), ntohs(client_addr.sin_port));
	                 printf("%s\n", peeraddrstr);
				 }
		 	 	
				tpool_add_work(pool,thread,peeraddrstr);
		 	}
     	}
     
	

	sleep(5);
	
	tpool_destroy(pool,1);
	log_close(logmy);
	pthread_exit(NULL);
}
Exemple #6
0
int
main (int argc, char **argv)
{
    int             opt = 0;                            /* Option Identifier */
    int             optindex = 0;                            /* Option Index */
    bool            isProfiling = false;      /* Are we profiling the cache? */
    bool            isPriming = false;          /* Are we priming the cache? */
    long            numCPUs = 0;                /* The number of online CPUs */
    struct dirent  *dp = NULL;                    /* Directory Entry Pointer */
    DIR            *dfd = NULL;                          /* Directory Stream */
    double          loadAverages[3] = { 0.00 };      /* System Load Averages */
    PGconn         *pgh = NULL;                /* Postgres Connection Handle */
    bool            isPWDRequired = false;     /* Is Postgres Password Reqd? */

    struct option   long_options[] =                 /* Options for getopt() */
    {
        {"connect-string",  required_argument,  NULL, 'c'},
        {"profile",         no_argument,        NULL, 'p'},
        {"prime",           no_argument,        NULL, 'w'},
        {"data-dir",        required_argument,  NULL, 'D'},
        {"postgres-only",   no_argument,        NULL, 'o'},
        {"sqlite-db",       required_argument,  NULL, 's'},
        {"help",            no_argument,        NULL, 'h'},
        {"debug",           no_argument,        NULL, 'd'},
        {NULL, 0, NULL, 0}
    };

    /* Go for the glory! */
    fprintf(stderr, "\n%s: Release %s - %s\n", PACKAGE_NAME,
        PACKAGE_VERSION, APP_RELEASE);
    fprintf(stderr, "\n%s\n\n", APP_COPYRIGHT);
    fflush(stdout);

    /* Process command-line options */
    while ((opt = getopt_long(argc, argv, "c:s:D:awhdp",
        long_options, &optindex)) != -1)
    {
        switch (opt)
        {
            case 'h':
                usage();
                exit(EXIT_SUCCESS);
                break;
            case 'p':
                if (isPriming == false)
                    isProfiling = true;
                else
                {
                    fprintf(stderr,
                        "Profiling and warming are mutually exlusive!\n");
                    exit(EXIT_FAILURE);
                }
                break;
            case 'w':
                if (isProfiling == false)
                    isPriming = true;
                else
                {
                    fprintf(stderr,
                        "Profiling and warming are mutually exlusive!\n");
                    exit(EXIT_FAILURE);
                }
                break;
            case 'd':
                is_debug = true;
                break;
            case 's':
                dbFileName = xstrdup(optarg);
                break;
            case 'c':
                pgConnectString = xstrdup(optarg);
                break;
            case 'D':
                pgDataDir = optarg;
                break;
            default:
                usage();
                exit(EXIT_FAILURE);
        }
    }

    /* Make sure user requested profile OR prime */
    if (isProfiling == false && isPriming == false)
    {
        fprintf(stderr, "Expected either -p or -w\n");
        usage();
        exit(EXIT_FAILURE);
    }

    /* Make sure the database name is set */

    /* Get the PG log file name from the end of the command line */
    if (optind < (argc - 1))
    {
        fprintf(stderr, "too many command-line arguments (first is \"%s\")\n",
                argv[optind + 1]);
        usage();
        exit(EXIT_FAILURE);
    }

    /* Perform a Postgres connection test & get password (if required) */
    do
    {
        isPWDRequired = false;
        pgh = PQsetdbLogin(NULL, NULL, NULL, NULL,
            pgConnectString == NULL ? "postgres"
                                    : pgConnectString,
            NULL, pgPassword);
        if (PQstatus(pgh) == CONNECTION_BAD)
        {
            if (PQconnectionNeedsPassword(pgh) && pgPassword == NULL)
            {
                printf("\nTesting Postgres Connection\n");
                PQfinish(pgh);
                pgPassword = simple_prompt("Password: "******"%s", "Connection Test Failed\n");
                ERROR_PRINT("SQLERRMC: %s\n", PQerrorMessage(pgh));
                PQfinish(pgh);
                exit(EXIT_FAILURE);
            }
        }
    } while (isPWDRequired);
    PQfinish(pgh);
    /* Get the number of available CPUs */
    numCPUs = sysconf(_SC_NPROCESSORS_ONLN);
    if (numCPUs < 1)
        numCPUs = 1;

    /*
     * Choose the number of CPUs to use in the thread pool based on load
     * average.  It only makes sense to do this if we have more than one CPU
     * to play with.
     */
    if ((numCPUs > 1)
        && (getloadavg(loadAverages, 3) == 3))
    {
        long    idleCPUs = 0;                     /* The number of idle CPUs */

        /* Show what we got */
        printf("load averages.... %3.2f %3.2f %3.2f\n",
            loadAverages[0], loadAverages[1], loadAverages[2]);

        /*
         * We're going to base the number of usable CPUs by subtracting
         * the sum of 1 (to account for OS and I/O overhead) plus the 1 minute
         * load average from the number of available CPUs.
         */
        idleCPUs = numCPUs - (1 + (int)(loadAverages[0] + 0.5));

        /* Assign # of available CPUs with some sanity checking */
        if (idleCPUs < numCPUs)
            numCPUs = idleCPUs;
        if (numCPUs < 1)
            numCPUs = 1;
    }

    /* Inform user of # of CPUs that will be used */
    printf("usable CPUs...... %d\n", numCPUs);

    /* If we have more than one CPU, multi-thread our operations */
    if (numCPUs > 1)
    {
        /* Initialize the thread pool */
        thp = tpool_init(numCPUs, 1024, true);
    }

    if (isProfiling)
        BuildCacheProfile();
    else /* isPriming */
        PrimeCache();

    /* If we have more than one CPU, multi-thread our operations */
    if (POINTER_IS_VALID(thp))
    {
        /* Destroy the thread pool */
        tpool_destroy(thp, 1); 
    }

    /* Cleanup */
    free(dbFileName);

    return EXIT_SUCCESS;

} /* main() */
Exemple #7
0
/*************************************************************
** MAIN
**	Reads the config file. Binds to a port. Launches the
**	worker and other threads. Listens for requests.
*/
int 
main(int argc, char **argv)
{
	char *		conf	= NULL;
	int	 	nthreads;
	int	 	c, ret;
	char**	 	ary;
	char*	 	prog;
	u_int		numfds		= 0;
	int	 	xerror;
	int	 	bg_flag	= TRUE;
	int	 	only_check_config;
	char		ebuf[BUFSIZ];
	char		nbuf[64];
	u_char *	gifimage	= NULL;
	u_char *	favicon		= NULL;
	int 		gifimagelen	= 0;
	int 		faviconlen	= 0;
	TPOOL_CTX *	tpool_ctx	= NULL;
	DEBUGS *	dp;
	LISTEN_CTX	*gctx		= NULL;
	LISTEN_CTX	*dctx		= NULL;
	LISTEN_CTX	*jctx		= NULL;
	pthread_t	gif_tid;
	pthread_t	data_tid;
	pthread_t	upload_tid;
#if HAVE_RESOURCE_H || HAVE_SYS_RESOURCE_H
	struct rlimit	rl;
#endif
	time_t		servertimeout;
	 
	prog = basename(argv[0]);
	if (prog == NULL)
		prog = argv[0];

	only_check_config = FALSE;
	servertimeout = 20;

	while ((c = getopt(argc, argv, "C:d:c:f")) != -1)
	{
		switch (c)
		{
			case 'f':
				bg_flag = FALSE;
				break;
			case 'C':
				only_check_config = TRUE;
				/*FALLTHROUGH*/
			case 'c':
				conf = optarg;
				break;
			case 'd':
				/*
				 * Debugging turned of if in background 
				 */
				if (bg_flag == TRUE)
					break;
				for (dp = DebugNames; dp->name != NULL; dp++)
				{
					if (strncasecmp(dp->name, optarg, strlen(optarg)) == 0)
					{
						setdebug(dp->flag);
						if (dp->flag == BUG_THREADS
							    || dp->flag == BUG_ALL)
							tpool_debug_set(TRUE);
						break;
					}
				}
				if (dp->name != NULL)
					break;
				printf("Unknown debug flag: %s, select from:\n", optarg);
				for (dp = DebugNames; dp->name != NULL; dp++)
					printf("\t%s\n", dp->name);
				return 0;
			case '?':
			default:
			usage:
				printf("Usage: %s "
					"[-c /path/onepixd.conf "
					"or "
					"-C /path/onepixd.conf] "
					"-d what "
					"[-f]\n",
					prog);
				return 0;
		}
	}
	if (argc != optind)
		goto usage;

	if (conf == NULL || strlen(conf) == 0)
	{
		(void) fprintf(stderr,
			"Required Parameter \"-c configfile\" missing.\n");
		goto usage;
	}
	ret = config_read_file(conf);
	if (ret != 0)
		return 0;

	/*
	 * All errors are logged, so we need to set up
	 * logging before checking the config file.
	 */
	ary = config_lookup(CONF_LOG_FACILITY);
	if (ary == NULL)
		ret = log_init(DEFAULT_LOG_FACILITY, prog);
	else
		ret = log_init(ary[0], prog);
	if (ret != 0)
		return 0;

	ret = config_validate();
	if (ret != 0)
		return 0;
	if (ret == 0 && only_check_config == TRUE)
		(void) printf("%s: FILE IS OKAY TO USE\n", conf);
	if (only_check_config == TRUE)
		return 0;


	ary = config_lookup(CONF_HOME_DIR);
	if (ary != NULL)
	{
		if (chdir(ary[0]) != 0)
		{
			xerror = errno;
			(void) snprintf(ebuf, sizeof ebuf,
				"Attempt to chdir(\"%s\"): %s",
				ary[0], strerror(xerror));
			log_emit(LOG_ERR, NULL, __FILE__, __LINE__, ebuf);
			goto shutdown_server;
		}
	}

	if (util_bg(bg_flag) != 0)
	{
		(void) snprintf(ebuf, sizeof ebuf, "fork(): %s\n", strerror(errno));
		log_emit(LOG_ERR, NULL, __FILE__, __LINE__, ebuf);
		goto shutdown_server;
	}


#if HAVE_RESOURCE_H || HAVE_SYS_RESOURCE_H
#ifdef RLIMIT_AS
	rl.rlim_cur = RLIM_INFINITY;
	rl.rlim_max = RLIM_INFINITY;
	(void) setrlimit(RLIMIT_AS, &rl); 	/* max size virtual memory */
#endif
#ifdef RLIMIT_CPU
	rl.rlim_cur = RLIM_INFINITY;
	rl.rlim_max = RLIM_INFINITY;
	(void) setrlimit(RLIMIT_CPU, &rl);	/* unlimited CPU usage */
#endif
#ifdef RLIMIT_DATA
	rl.rlim_cur = RLIM_INFINITY;
	rl.rlim_max = RLIM_INFINITY;
	(void) setrlimit(RLIMIT_DATA, &rl);	/* unlimited memory */
#endif
#ifdef RLIMIT_FSIZE
	rl.rlim_cur = RLIM_INFINITY;
	rl.rlim_max = RLIM_INFINITY;
	(void) setrlimit(RLIMIT_FSIZE, &rl);	/* unlimited file sizes */
#endif
#ifdef RLIMIT_STACK
	rl.rlim_cur = RLIM_INFINITY;
	rl.rlim_max = RLIM_INFINITY;
	(void) setrlimit(RLIMIT_STACK, &rl);	/* unlimited stack */
#endif
#ifdef RLIMIT_CORE
	rl.rlim_cur = RLIM_INFINITY;
	rl.rlim_max = RLIM_INFINITY;
	(void) setrlimit(RLIMIT_CORE, &rl);	/* allow core dumps */
#endif
#ifdef RLIMIT_NOFILE
	rl.rlim_cur = RLIM_INFINITY;
	rl.rlim_max = RLIM_INFINITY;
	(void) setrlimit(RLIMIT_NOFILE, &rl);	/* maximum file descriptors */
	(void) getrlimit(RLIMIT_NOFILE, &rl);
	numfds = (rl.rlim_cur);

#endif
#endif /* HAVE_RESOURCE_H */

	ary = config_lookup(CONF_BECOME_USER);
	if (ary != NULL)
	{
		/*
		 * Note that setrunasuser() logs its own errors 
		 */
		if (setrunasuser(ary[0]) != 0)
			goto shutdown_server;
	}

	ary = config_lookup(CONF_NUMTHREADS);
	if (ary == NULL)
		nthreads = DEFAULT_THREADS;
	else
	{
		nthreads = strtoul(ary[0], NULL, 10);
		if (nthreads <= 0)
		{
			(void) fprintf(stderr,
				"Configuration item \"%s\" illegal value: %d.\n", 
					CONF_NUMTHREADS, nthreads);
			return 0;
		}
	}
	if (numfds == 0 || numfds > (nthreads * 3))
		numfds = nthreads * 3;
	(void) io_init(numfds);

	gifimage = gif_get1x1gif(&gifimagelen);
	if (gifimage == NULL)
	{
		(void) snprintf(ebuf, sizeof ebuf, "Load gif image: %s\n", strerror(errno));
		log_emit(LOG_ERR, NULL, __FILE__, __LINE__, ebuf);
		goto shutdown_server;
	}
	favicon  = gif_getfavicon_ico(&faviconlen);

	/*
	 * Prepare to launch the thread to listen for inbound
	 * gif requests.
	 */
	gctx = str_alloc(sizeof(LISTEN_CTX), 1, __FILE__, __LINE__);
	if (gctx == NULL)
	{
		(void) snprintf(ebuf, sizeof ebuf, "alloc(): %s\n", strerror(errno));
		log_emit(LOG_ERR, NULL, __FILE__, __LINE__, ebuf);
		goto shutdown_server;
	}
	gctx->type = LISTEN_TYPE_GIF;
	/* gif image only, no favicon */
	gctx->gifimage = gifimage;
	gctx->gifimagelen = gifimagelen;
	gctx->favicon  = NULL;
	gctx->faviconlen = 0;
	ary = config_lookup(CONF_GIF_PORT);
	if (ary == NULL)
		(void) strlcpy(gctx->port, "80", sizeof gctx->port);
	else
		(void) strlcpy(gctx->port, ary[0], sizeof gctx->port);

	ary = config_lookup(CONF_GIF_INTERFACE);
	if (ary == NULL)
		(void) strlcpy(gctx->interface, "INADDR_ANY", sizeof gctx->interface);
	else
		(void) strlcpy(gctx->interface, ary[0], sizeof gctx->interface);

	/*
	 * Everything from here down must be thread safe.
	 */

	tpool_ctx = tpool_init(nthreads, ebuf, sizeof ebuf);
	if (tpool_ctx == NULL)
		goto shutdown_server;
	gctx->tpool_ctx = tpool_ctx;


	/*
	 * The GIF server may have to bind to a privaliged port, such
	 * as port 80, so we launch it and expect it to change the
	 * user id after its bind.
	 */
	ret = pthread_create(&gif_tid, NULL, thread_listener, (void *)gctx);
	if (ret != 0)
	{
	}

	/*
	 * Prepare to launch the thread to listen for inbound
	 * data requests.
	 */
	dctx = str_alloc(sizeof(LISTEN_CTX), 1, __FILE__, __LINE__);
	if (dctx == NULL)
	{
		(void) snprintf(ebuf, sizeof ebuf, "alloc(): %s\n", strerror(errno));
		log_emit(LOG_ERR, NULL, __FILE__, __LINE__, ebuf);
		goto shutdown_server;
	}
	dctx->type = LISTEN_TYPE_DATA;
	/* a favicon only, no gif */
	dctx->gifimage = NULL;
	dctx->favicon  = favicon;
	dctx->gifimagelen = 0;
	dctx->faviconlen  = faviconlen;
	ary = config_lookup(CONF_DATA_PORT);
	if (ary == NULL)
		(void) strlcpy(dctx->port, "8100", sizeof dctx->port);
	else
		(void) strlcpy(dctx->port, ary[0], sizeof dctx->port);

	ary = config_lookup(CONF_DATA_INTERFACE);
	if (ary == NULL)
		(void) strlcpy(dctx->interface, "INADDR_ANY", sizeof dctx->interface);
	else
		(void) strlcpy(dctx->interface, ary[0], sizeof dctx->interface);

	dctx->tpool_ctx = tpool_ctx;

	ret = pthread_create(&data_tid, NULL, thread_listener, (void *)dctx);
	if (ret != 0)
	{
	}

	/*
	 * Prepare to launch the thread to listen for uploads of more.
	 */
	(void) verify_threads_locking_init();
	jctx = str_alloc(sizeof(LISTEN_CTX), 1, __FILE__, __LINE__);
	if (jctx == NULL)
	{
		(void) snprintf(ebuf, sizeof ebuf, "alloc(): %s\n", strerror(errno));
		log_emit(LOG_ERR, NULL, __FILE__, __LINE__, ebuf);
		goto shutdown_server;
	}
	jctx->type = LISTEN_TYPE_UPLOAD;
	/* a favicon only, no gif */
	jctx->gifimage = NULL;
	jctx->favicon  = favicon;
	jctx->gifimagelen = 0;
	jctx->faviconlen  = faviconlen;
	ary = config_lookup(CONF_UPLOAD_PORT);
	if (ary == NULL)
		(void) strlcpy(jctx->port, "8101", sizeof jctx->port);
	else
		(void) strlcpy(jctx->port, ary[0], sizeof jctx->port);

	ary = config_lookup(CONF_UPLOAD_INTERFACE);
	if (ary == NULL)
		(void) strlcpy(jctx->interface, "INADDR_ANY", sizeof jctx->interface);
	else
		(void) strlcpy(jctx->interface, ary[0], sizeof jctx->interface);

	jctx->tpool_ctx = tpool_ctx;

	ret = pthread_create(&upload_tid, NULL, thread_listener, (void *)jctx);
	if (ret != 0)
	{
	}

	ary = config_lookup(CONF_PIDFILE);
	if (ary != NULL)
	{
		/*
		 * Note that write_pid_file() logs its own errors 
		 */
		if (write_pid_file(ary[0]) != 0)
			goto shutdown_server;
	}

	(void) strlcpy(ebuf, "Startup: version=", sizeof ebuf);
	(void) strlcat(ebuf, VERSION, sizeof ebuf);
	(void) strlcat(ebuf, ", gif_interface=", sizeof ebuf);
	(void) strlcat(ebuf, gctx->interface, sizeof ebuf);
	(void) strlcat(ebuf, ", gif_port=", sizeof ebuf);
	(void) strlcat(ebuf, gctx->port, sizeof ebuf);
	(void) strlcat(ebuf, ", data_interface=", sizeof ebuf);
	(void) strlcat(ebuf, dctx->interface, sizeof ebuf);
	(void) strlcat(ebuf, ", data_port=", sizeof ebuf);
	(void) strlcat(ebuf, dctx->port, sizeof ebuf);
	(void) strlcat(ebuf, ", threads=", sizeof ebuf);
	(void) str_ultoa(nthreads, nbuf, sizeof nbuf);
	(void) strlcat(ebuf, nbuf, sizeof ebuf);
	log_emit(LOG_INFO, NULL, __FILE__, __LINE__, ebuf);


	Global_Die = FALSE;

	(void) signal(SIGINT,  catch_sig);
	(void) signal(SIGQUIT, catch_sig);
	(void) signal(SIGKILL, catch_sig);
	(void) signal(SIGTERM, catch_sig);
	(void) signal(SIGPIPE, SIG_IGN);

	if (Global_Die == TRUE)
		goto shutdown_server;
	(void) file_prune_garbage(&Global_Die);


shutdown_server:
	Global_Die = TRUE;

	(void) pthread_join(data_tid, NULL);
	(void) pthread_join(gif_tid, NULL);
	(void) pthread_join(upload_tid, NULL);

	(void) verify_threads_locking_shutdown();

	if (tpool_ctx != NULL)
		tpool_ctx = tpool_shutdown(tpool_ctx, ebuf, sizeof ebuf);

	if (gctx != NULL)
		gctx = str_free(gctx, __FILE__, __LINE__);
	if (dctx != NULL)
		dctx = str_free(dctx, __FILE__, __LINE__);
	if (jctx != NULL)
		jctx = str_free(jctx, __FILE__, __LINE__);
	if (gifimage != NULL)
		gifimage = str_free(gifimage, __FILE__, __LINE__);
	if (favicon != NULL)
		favicon = str_free(favicon, __FILE__, __LINE__);

	ary = config_lookup(CONF_PIDFILE);
	if (ary != NULL)
		(void) unlink(ary[0]);

	io_shutdown();
	config_shutdown();

	(void) strlcpy(ebuf, "Shutdown: version=", sizeof ebuf);
	(void) strlcat(ebuf, VERSION, sizeof ebuf);
	log_emit(LOG_INFO, NULL, __FILE__, __LINE__, ebuf);
	/*
	 * This str_shutdown must always be last.
	 */
	str_shutdown();

	return 0;
}