Пример #1
0
iface_t *iface_bind(int family, int port)
{
	iface_t *iface;

	iface = iface_create(family);
	if(iface != NULL)
	{
		if(family == AF_INET)
		{
			((struct sockaddr_in *) iface->addr)->sin_port = htons(port);
		}
		else if(family == AF_INET6)
		{
			((struct sockaddr_in6 *) iface->addr)->sin6_port = htons(port);
		}

		iface->socket_fd = socket(family, SOCK_STREAM, 0);
		if(iface->socket_fd == -1)
		{
			iface_destroy(iface);
			iface = NULL;
		}
		else
		{
			if(family == AF_INET)
			{
				if(inet_pton(family, "localhost", &(((struct sockaddr_in *) iface->addr)->sin_addr)) == -1)
				{
					iface_destroy(iface);
					iface = NULL;
				}
			}
			else if(family == AF_INET6)
			{
				if(inet_pton(family, "localhost", &(((struct sockaddr_in6 *) iface->addr)->sin6_addr)) == -1)
				{
					iface_destroy(iface);
					iface = NULL;
				}
			}

			if(iface != NULL)
			{
				bind(iface->socket_fd, iface->addr, iface->addrlen);
				listen(iface->socket_fd, 5);
			}
		}
	}

	return iface;
}
Пример #2
0
int main(int argc, char ** argv)
{
    long templ;
    pthread_t tid;
    pid_t pid;
    char *config=NULL;
    iface_t  *engine;
    struct if_engine *ifg;
    iface_t *ifptr,*ifptr2,*rptr;
    iface_t **tiptr;
    unsigned int i=1;
    int opt,err=0;
    void *ret;
    struct kopts *options=NULL;
    sigset_t set;
    struct iolists lists = {
        /* initialize io_mutex separately below */
        .init_mutex = PTHREAD_MUTEX_INITIALIZER,
        .init_cond = PTHREAD_COND_INITIALIZER,
        .dead_cond = PTHREAD_COND_INITIALIZER,
    .initialized = NULL,
    .outputs = NULL,
    .inputs = NULL,
    .dead = NULL
    };
    struct rlimit lim;
    int gotinputs=0;
    int rcvdsig;
    struct sigaction sa;

    pthread_mutex_init(&lists.io_mutex,NULL);

    /* command line argument processing */
    while ((opt=getopt(argc,argv,"d:f:o:V")) != -1) {
        switch (opt) {
            case 'd':
                if ((((templ=strtol(optarg,NULL,0)) == 0) &&
                        (errno == EINVAL || errno == ERANGE )) ||
                        (templ < 0) || (templ > 9)) {
                    logerr(errno,"Bad debug level %s: Must be 1-9",optarg);
                    err++;
                } else
                    debuglevel=templ;
                break;
            case 'o':
                if (cmdlineopt(&options,optarg) < 0)
                    err++;
                break;
            case 'f':
                config=optarg;
                break;
            case 'V':
                printf("%s\n",VERSION);
                if (argc == 2)
                    exit(0);
                else
                    err++;
                break;
            default:
                err++;
        }
    }

    if (err) {
        fprintf(stderr, "Usage: %s [-V] | [ -f <config file>] [-o <option=value>]... [<interface specification> ...]\n",argv[0]);
        exit(1);
    }

    /* If a config file is specified by a commad line argument, read it.  If
     * not, look for a default config file unless told not to using "-f-" on the
     * command line
     */
    if ((config && (strcmp(config,"-"))) ||
            (!config && (config = get_def_config()))) {
        DEBUG(1,"Using config file %s",config);
        if ((engine=parse_file(config)) == NULL) {
            fprintf(stderr,"Error parsing config file: %s\n",errno?
                    strerror(errno):"Syntax Error");
            exit(1);
        }
    } else {
        /* global options for engine configuration are also returned in config
         * file parsing. If we didn't do that, get default options here */
        DEBUG(1,"Not using  config file");
        engine = get_default_global();
    }

    proc_engine_options(engine,options);

    engine->lists = &lists;
    lists.engine=engine;

    for (tiptr=&engine->next;optind < argc;optind++) {
        if (!(ifptr=parse_arg(argv[optind]))) {
            fprintf(stderr,"Failed to parse interface specifier %s\n",
                    argv[optind]);
            exit(1);
        }
        ifptr->next=(*tiptr);
        (*tiptr)=ifptr;
        tiptr=&ifptr->next;
    }

    /* We choose to go into the background here before interface initialzation
     * rather than later. Disadvantage: Errors don't get fed back on stderr.
     * Advantage: We can close all the file descriptors now rather than pulling
     * then from under erroneously specified stdin/stdout etc.
     */

    ifg=(struct if_engine *)engine->info;
    if (ifg->flags & K_BACKGROUND) {
         if ((pid = fork()) < 0) {
            perror("fork failed");
            exit(1);
        } else if (pid)
            exit(0);

        /* Continue here as child */

        /* Really should close all file descriptors. Harder to do in OS
         * independent way.  Just close the ones we know about for this cut
         * Check first if connected to a tty to allow redirection / piping in
         * background mode
         */
        if (isatty(fileno(stdin))) {
            fclose(stdin);
            ifg->flags |= K_NOSTDIN;
        }
        if (isatty(fileno(stdout))) {
            fclose(stdout);
            ifg->flags |= K_NOSTDOUT;
        }
        if (isatty(fileno(stderr))) {
            fclose(stderr);
            ifg->flags |= K_NOSTDERR;
        }
        setsid();
        (void) chdir("/");
        umask(0);
    }

    /* log to stderr or syslog, as appropriate */
    initlog((ifg->flags & K_NOSTDERR)?ifg->logto:-1);

    /* Lower max open files if necessary. We do this to ensure that ids for
     * all connections can be represented in IDMINORBITS. Actually we only
     * need to do that per server, so this is a bit of a hack and should be
     * corrected
     */
    if (getrlimit(RLIMIT_NOFILE,&lim) < 0)
            logterm(errno,"Couldn't get resource limits");
    if (lim.rlim_cur > 1<<IDMINORBITS) {
        logwarn("Lowering NOFILE from %u to %u",lim.rlim_cur,1<<IDMINORBITS);
        lim.rlim_cur=1<<IDMINORBITS;
        if(setrlimit(RLIMIT_NOFILE,&lim) < 0)
            logterm(errno,"Could not set file descriptor limit");
    }

    /* our list of "real" interfaces starts after the first which is the
     * dummy "interface" specifying the multiplexing engine
     * walk the list, initialising the interfaces.  Sometimes "BOTH" interfaces
     * are initialised to one IN and one OUT which then need to be linked back
     * into the list
     */
    for (ifptr=engine->next,tiptr=&lists.initialized,i=0;ifptr;ifptr=ifptr2) {
        ifptr2 = ifptr->next;

        if (i == MAXINTERFACES)
            logterm(0,"Too many interfaces");
        ifptr->id=++i<<IDMINORBITS;
        if (ifptr->name) {
            if (insertname(ifptr->name,ifptr->id) < 0)
                logterm(errno,"Failed to associate interface name and id");
        }

        ifptr->lists = &lists;

        if ((rptr=(*iftypes[ifptr->type].init_func)(ifptr)) == NULL) {
            logerr(0,"Failed to initialize Interface %s",(ifptr->name)?
                    ifptr->name:"(unnamed)");
            if (!flag_test(ifptr,F_OPTIONAL)) {
                timetodie++;
                break;
            }
            /* Free all resources associated with interface
             * This is a bigger task than it looks.  Before the "optional"
             * flag this was not an issue as we'd just be exiting after this
             * Now we need to clean up properly but not yet implemented.  This
             * is a little memory leak with each failed init attempt
             */
            free(ifptr);
            continue;
        }
        for (;ifptr;ifptr = ifptr->next) {
        /* This loop should be done once for IN or OUT interfaces twice for
         * interfaces where the initialisation routine has expanded them to an
         * IN/OUT pair.
         */
            if (ifptr->direction == IN)
                ifptr->q=engine->q;

            if (ifptr->checksum <0)
                ifptr->checksum = engine->checksum;
            if (ifptr->strict <0)
                ifptr->strict = engine->strict;
            (*tiptr)=ifptr;
            tiptr=&ifptr->next;
            if (ifptr->next==ifptr2)
                ifptr->next=NULL;
        }
    }

    /* One more spin through the list now we've initialised the name to id
     * mapping so we can update references to "name" with an id
     */
    for (ifptr=engine->next;ifptr;ifptr=ifptr->next) {
        if (ifptr->ofilter)
            if (name2id(ifptr->ofilter))
                logterm(errno,"Name to interface translation failed");
    }

    /* Create the key for thread local storage: in this case for a pointer to
     * the interface each thread is handling
     */
    if (pthread_key_create(&ifkey,iface_destroy)) {
        logerr(errno,"Error creating key");
        timetodie++;
    }

    if (timetodie) {
        for (ifptr=lists.initialized;ifptr;ifptr=ifptr2) {
            ifptr2=ifptr->next;
            iface_destroy(ifptr);
        }
        exit(1);
    }

    if (name2id(engine->ofilter))
            logterm(errno,"Failed to translate interface names to IDs");

    if (engine->options)
        free_options(engine->options);

    pthread_setspecific(ifkey,(void *)&lists);
    reaper=pthread_self();

    sigemptyset(&set);
    sigemptyset(&sa.sa_mask);
    sa.sa_handler=terminate;
    sa.sa_flags=0;
    sigaction(SIGUSR1,&sa,NULL);

    sigaddset(&set,SIGUSR1);
    sigaddset(&set,SIGUSR2);
    sigaddset(&set,SIGALRM);
    sigaddset(&set,SIGTERM);
    sigaddset(&set,SIGINT);
    pthread_sigmask(SIG_BLOCK, &set, NULL);
    sigdelset(&set,SIGUSR1);
    signal(SIGPIPE,SIG_IGN);
    pthread_create(&tid,NULL,run_engine,(void *) engine);

    pthread_mutex_lock(&lists.io_mutex);
    for (ifptr=lists.initialized;ifptr;ifptr=ifptr->next) {
        /* Check we've got at least one input */
        if ((ifptr->direction == IN ) || (ifptr->direction == BOTH))
            gotinputs=1;
        /* Create a thread to run each interface */
        pthread_create(&tid,NULL,(void *)start_interface,(void *) ifptr);
    }

    while (lists.initialized)
        pthread_cond_wait(&lists.init_cond,&lists.io_mutex);

    /* Have to wait until here to do something about no inputs to
     * avoid deadlock on io_mutex
     */
    if (!gotinputs) {
        logerr(0,"No Inputs!");
        pthread_mutex_lock(&engine->q->q_mutex);
        engine->q->active=0;
        pthread_cond_broadcast(&engine->q->freshmeat);
        pthread_mutex_unlock(&engine->q->q_mutex);
        timetodie++;
    }

    /* While there are remaining outputs, wait until something is added to the 
     * dead list, reap everything on the dead list and check for outputs again
     * until all the outputs have been reaped
     * Note that when there are no more inputs, we set the
     * engine's queue inactive causing it to set all the outputs' queues
     * inactive and shutting them down. Thus the last input exiting also shuts
     * everything down */
    while (lists.outputs || lists.inputs || lists.dead) {
        if (lists.dead  == NULL && (timetodie <= 0)) {
            pthread_mutex_unlock(&lists.io_mutex);
            /* Here we're waiting for SIGTERM/SIGINT (user shutdown requests),
             * SIGUSR2 (notifications of termination from interface threads)
             * and (later) SIGALRM to notify of the grace period expiry
             */
            (void) sigwait(&set,&rcvdsig);
            pthread_mutex_lock(&lists.io_mutex);
        }

        if ((timetodie > 0) || ( lists.outputs == NULL && (timetodie == 0)) ||
                rcvdsig == SIGTERM || rcvdsig == SIGINT) {
            timetodie=-1;
            /* Once we've caught a user shutdown address we don't need to be
             * told twice
             */
            signal(SIGTERM,SIG_IGN);
            signal(SIGINT,SIG_IGN);
            sigdelset(&set,SIGTERM);
            sigdelset(&set,SIGINT);
            for (ifptr=lists.inputs;ifptr;ifptr=ifptr->next) {
                pthread_kill(ifptr->tid,SIGUSR1);
            }
            for (ifptr=lists.outputs;ifptr;ifptr=ifptr->next) {
                if (ifptr->q == NULL)
                    pthread_kill(ifptr->tid,SIGUSR1);
            }
            /* Set up the graceperiod alarm */
            if (graceperiod)
                alarm(graceperiod);
        }
        if (rcvdsig == SIGALRM || graceperiod == 0) {
            sigdelset(&set,SIGALRM);
            /* Make sure we don't come back here with 0 graceperiod */
            if (graceperiod == 0)
                graceperiod=1;
            for (ifptr=lists.outputs;ifptr;ifptr=ifptr->next) {
                if (ifptr->q)
                    pthread_kill(ifptr->tid,SIGUSR1);
            }
        }
        for (ifptr=lists.dead;ifptr;ifptr=lists.dead) {
            lists.dead=ifptr->next;
            pthread_join(ifptr->tid,&ret);
            free(ifptr);
        }
    }

    /* For neatness... */
    pthread_mutex_unlock(&lists.io_mutex);

    exit(0);
}