Exemple #1
0
/**
 * Initializes this module:
 *     - Opens the product-queue named by `getQueuePath()`;
 *     - Redirects the standard input stream to the given input file;
 *     - Initializes the structure `prod`; and
 *     - Initializes the PRNG module associated with the function `random()`.
 *
 * @retval    true           if and only if successful.
 */
static bool pti_init(void)
{
    int               success = false;
    const char* const pqfname = getQueuePath();
    int               status = pq_open(pqfname, PQ_DEFAULT, &pq);
    if (PQ_CORRUPT == status) {
        log_add("The product-queue \"%s\" is corrupt\n", pqfname);
    }
    else if (status) {
        log_errno_q(status, "Couldn't open product-queue \"%s\"", pqfname);
    }
    else {
        prod.data = malloc(max_prod_size);
        if (prod.data == NULL) {
            log_syserr_q("Couldn't allocate buffer for data-product");
        }
        else {
            (void)strncpy(myname, ghostname(), sizeof(myname));
            myname[sizeof(myname)-1] = 0;
            prod.info.origin = myname;
            prod.info.feedtype = feedtype;
            srandom(1); // for `random()`
            seed[2] = random(); seed[1] = random(); seed[0] = random();
            (void)seed48(seed); // for `mrand48()`
            success = true;
        }
    }

    return success;
}
Exemple #2
0
/*
 * Sends a single, open file to an LDM as a data-product. The number of bytes
 * to be sent is specified by the data-product's metadata. The bytes start at
 * the beginning of the file.
 *
 * Arguments:
 *      proxy           The LDM proxy data-structure.
 *      fd              The file-descriptor open on the file to be sent.
 *      info            The data-product's metadata. Must be completely set.
 *
 * Returns:
 *      0                       Success.
 *      SYSTEM_ERROR            O/S failure. "log_add()" called.
 *      CONNECTION_ABORTED      The connection was aborted. "log_add()"
 *                              called.
 */
static int
send_product(
    LdmProxy*           proxy,
    int                 fd,
    prod_info* const    info)
{
    int                 status;
    product             product;

    product.info = *info;
    product.data = mmap(NULL, info->sz, PROT_READ, MAP_PRIVATE, fd, 0);

    if (MAP_FAILED == product.data) {
        log_syserr_q("Couldn't memory-map file");
        status = SYSTEM_ERROR;
    }
    else {
        status = lp_send(proxy, &product);
        if (LP_UNWANTED == status) {
            log_notice_q("Unwanted product: %s", s_prod_info(NULL, 0, info,
                        log_is_enabled_debug));
            status = 0;
        }
        (void)munmap(product.data, info->sz);
    }                                           /* file is memory-mapped */

    return status;
}
Exemple #3
0
/**
 * Returns the process-ID that's contained in a file.
 *
 * @param[in] pathname  The pathname of the file.
 * @retval     0        The file doesn't exist.
 * @retval    -1        Error. `log_add()` called.
 * @return              The process-ID that was in the file.
 */
static pid_t
getPidFromFile(
    const char* const pathname)
{
    long  pid;
    FILE* file = fopen(pathname, "r");

    if (file == NULL) {
        if (errno == ENOENT) {
            pid = 0;
        }
        else {
            log_syserr_q("Couldn't open PID file \"%s\"", pathname);
            pid = -1;
        }
    }
    else {
        pid = parsePid(file);

        if (pid == -1)
            log_add("Couldn't get PID from file \"%s\"", pathname);

        (void)fclose(file);
    } // `file` is open

    return pid;
}
Exemple #4
0
ErrorObj*
err_new(
    const int           code,
    ErrorObj* const     cause,
    const char* const   file,
    const unsigned      line, 
    const char* const   fmt,
    ...)
{
    ErrorObj *err;

    log_assert(file != NULL);

    err = (ErrorObj*)malloc(sizeof(ErrorObj));

    if (NULL == err) {
        log_syserr_q("malloc(%lu) failure",
            (unsigned long)sizeof(ErrorObj));
    }
    else {
        err->line = line;
        err->file = file;

        if (NULL == fmt) {
            err->msg[0] = 0;
            err->msglen = 0;
            err->code = code;
            err->cause = cause;
        }
        else {
            va_list     args;
            int         nbytes;
            size_t      size = sizeof(err->msg);

            va_start(args, fmt);

            nbytes = vsnprintf(err->msg, size, fmt, args);
            if (nbytes < 0) {
                nbytes = snprintf(err->msg, size, 
                    "err_new(): vsnprintf() failure: \"%s\"", fmt);
            }
            else if (nbytes >= size) {
                nbytes = size - 1;
            }

            va_end(args);

            err->msg[nbytes] = 0;
            err->msglen = (size_t)nbytes;

            log_assert(err->msglen < size);

            err->code = code;
            err->cause = cause;
        }
    }                                   /* "err" allocated */

    return err;
}
Exemple #5
0
/*
 * Allocates memory.
 *
 * Arguments:
 *      nbytes          The number of bytes to allocate
 *      status          Pointer to the status variable to be set.  Shall not be
 *                      NULL.  Upon successful return, "*status" will be 0;
 *                      otherwise it will be ENOMEM.
 * Returns:
 *      NULL            System error.  "log_add()" called.  "*status" is
 *                      ENOMEM.
 *      else            A pointer to the allocated memory.  "*status" is 0.
 */
void* reg_malloc(
    const size_t        nbytes,
    RegStatus* const    status)
{
    void*       ptr = malloc(nbytes);

    if (NULL == ptr) {
        log_syserr_q("Couldn't allocate %lu bytes", nbytes);
        *status = ENOMEM;
    }
    else {
        *status = 0;
    }

    return ptr;
}
Exemple #6
0
/**
 * Returns the process-ID that's contained in a file.
 *
 * @param[in] file      The file that contains the PID.
 * @retval    -1        Error. `log_add()` called.
 * @return              The process-ID that was in the file.
 */
static pid_t
parsePid(
    FILE* const file)
{
    long pid;

    if (fscanf(file, "%ld", &pid) != 1) {
        if (ferror(file)) {
            log_syserr_q("Couldn't parse PID");
        }
        else {
            log_add("Couldn't parse PID");
        }
        pid = -1;
    }

    return pid;
}
Exemple #7
0
static int
fd_md5(MD5_CTX *md5ctxp, int fd, off_t st_size, signaturet signature)
{
    ssize_t     nread;
    char        buf[8192];

    MD5Init(md5ctxp);

    for (; exitIfDone(1) && st_size > 0; st_size -= (off_t)nread) {
        nread = read(fd, buf, sizeof(buf));
        if(nread <= 0) {
            log_syserr_q("fd_md5: read");
            return -1;
        } /* else */
        MD5Update(md5ctxp, (unsigned char *)buf, (unsigned int)nread);
    }

    MD5Final((unsigned char*)signature, md5ctxp);
    return 0;
}
Exemple #8
0
static int
fd_md5(MD5_CTX *md5ctxp, int fd, off_t st_size, signaturet signature)
{
        int           nread;
        unsigned char buf[8192];

        MD5Init(md5ctxp);
        for(; st_size > 0; st_size -= nread )
        {
                nread = read(fd, buf, sizeof(buf));
                if(nread <= 0)
                {
                        log_syserr_q("fd_md5: read");
                        return -1;
                } /* else */
                MD5Update(md5ctxp, buf, nread);
                (void)exitIfDone(1);
        }
        MD5Final(signature, md5ctxp);
        return 0;
}
Exemple #9
0
/*
 * Clones the prefix of a string.  Logs a message if an error occurs.
 *
 * ARGUMENTS:
 *      clone           Pointer to a pointer to the clone.  Set upon successful
 *                      return.  Shall not be NULL.  The client should call
 *                      "free(*clone)" when the clone is no longer needed.
 *      string          Pointer to the string to clone.  Shall not be NULL.
 *      nbytes          The number of bytes of prefix to clone
 * RETURNS:
 *      0               Success.  "*clone" is not NULL.
 *      ENOMEM          System error.  "log_add()" called.
 */
RegStatus reg_clonePrefix(
    char** const        clone,
    const char* const   string,
    size_t              nbytes)
{
    RegStatus   status;
    char*       copy = (char*)reg_malloc(nbytes+1, &status);

    if (NULL != copy) {
        strncpy(copy, string, nbytes)[nbytes] = 0;
        *clone = copy;
        status = 0;
    }
    else {
        log_syserr_q("Couldn't clone first %lu bytes of string \"%s\"",
            nbytes, string);
        status = ENOMEM;
    }

    return status;
}
Exemple #10
0
int
main(int ac, char *av[])
{
        int          status = 0;
        char*        logfname = 0;
        /// Data directory, conffile paths may be relative
        const char*  datadir;
        int          interval = DEFAULT_INTERVAL;
        prod_spec    spec;
        prod_class_t clss;
        int          toffset = TOFFSET_NONE;
        int          loggingToStdErr = 0;
        unsigned     queue_size = 5000;
        const char*  progname = basename(av[0]);
        unsigned     logopts = LOG_CONS|LOG_PID;

        /*
         * Setup default logging before anything else.
         */
        (void)log_init(progname);

        const char*  pqfname = getQueuePath();

        spec.feedtype = DEFAULT_FEEDTYPE;
        spec.pattern = DEFAULT_PATTERN;

        if(set_timestamp(&clss.from)) /* corrected by toffset below */
        {
                int errnum = errno;
                log_error_q("Couldn't set timestamp: %s", strerror(errnum));
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }
        clss.to = TS_ENDT;
        clss.psa.psa_len = 1;
        clss.psa.psa_val = &spec;

        /*
         * deal with the command line, set options
         */
        {
            extern int optind;
            extern int opterr;
            extern char *optarg;

            int ch;
            int fterr;

            opterr = 1;

            while ((ch = getopt(ac, av, "vxel:d:f:q:o:p:i:t:")) != EOF) {
                switch (ch) {
                case 'v':
                        if (!log_is_enabled_info)
                            (void)log_set_level(LOG_LEVEL_INFO);
                        break;
                case 'x':
                        (void)log_set_level(LOG_LEVEL_DEBUG);
                        break;
                case 'e':
                        key = ftok("/etc/rc.d/rc.local",'R');
                        semkey = ftok("/etc/rc.d/rc.local",'e');
                        shmid = shmget(key, sizeof(edex_message) * queue_size,
                                0666 | IPC_CREAT);
                        semid = semget(semkey, 2, 0666 | IPC_CREAT);
                        break;
                case 'l':
                        logfname = optarg;
                        (void)log_set_destination(logfname);
                        break;
                case 'd':
                        setPqactDataDirPath(optarg);
                        break;
                case 'f':
                        fterr = strfeedtypet(optarg, &spec.feedtype);
                        if(fterr != FEEDTYPE_OK)
                        {
                                log_error_q("Bad feedtype \"%s\", %s\n",
                                        optarg, strfeederr(fterr));
                                usage(progname);
                        }
                        break;
                case 'q':
                        pqfname = optarg;
                        break;
                case 'o':
                        toffset = atoi(optarg);
                        if(toffset == 0 && *optarg != '0')
                        {
                                log_error_q("invalid offset %s\n", optarg);
                                usage(progname);   
                        }
                        break;
                case 'i':
                        interval = atoi(optarg);
                        if(interval == 0 && *optarg != '0')
                        {
                                log_error_q("invalid interval %s\n", optarg);
                                usage(progname);   
                        }
                        break;
                case 't':
                        pipe_timeo = atoi(optarg);
                        if(pipe_timeo == 0 && *optarg != 0)
                        {
                                log_error_q("invalid pipe_timeo %s", optarg);
                                usage(progname);   
                        }
                        break;
                case 'p':
                        spec.pattern = optarg;
                        break;
                default:
                        usage(progname);
                        break;
                }
            }

            conffilename = getPqactConfigPath();
            datadir = getPqactDataDirPath();

            {
                int numOperands = ac - optind;

                if (1 < numOperands) {
                    log_error_q("Too many operands");
                    usage(progname);
                }
                else if (1 == numOperands) {
                    conffilename = av[optind];
                }
            }
        }

        setQueuePath(pqfname);
        log_notice_q("Starting Up");

        if ('/' != conffilename[0]) {
            /*
             * The pathname of the configuration-file is relative. Convert it
             * to absolute so that it can be (re)read even if the current
             * working directory changes.
             */
#ifdef PATH_MAX
            char    buf[PATH_MAX];          /* includes NUL */
#else
            char    buf[_POSIX_PATH_MAX];   /* includes NUL */
#endif
            if (getcwd(buf, sizeof(buf)) == NULL) {
                log_syserr_q("Couldn't get current working directory");
                exit(EXIT_FAILURE);
            }
            (void)strncat(buf, "/", sizeof(buf)-strlen(buf)-1);
            (void)strncat(buf, conffilename, sizeof(buf)-strlen(buf)-1);
            conffilename = strdup(buf);
            if (conffilename == NULL) {
                log_syserr_q("Couldn't duplicate string \"%s\"", buf);
                exit(EXIT_FAILURE);
            }
        }

        /*
         * Initialize the previous-state module for this process.
         */
        if (stateInit(conffilename) < 0) {
            log_error_q("Couldn't initialize previous-state module");
            exit(EXIT_FAILURE);
            /*NOTREACHED*/
        }

        /*
         * Configure the standard I/O streams for execution of child processes.
         */
        if (configure_stdio_file_descriptors()) {
            log_error_q("Couldn't configure standard I/O streams for execution "
                    "of child processes");
            exit(EXIT_FAILURE);
        }

        /*
         * Inform the "filel" module about the number of available file
         * descriptors.  File descriptors are reserved for stdin, stdout,
         * stderr, the product-queue, the configuration-file, and (possibly) 
         * logging.
         */
        if (0 != set_avail_fd_count(openMax() - 6))
        {
            log_error_q("Couldn't set number of available file-descriptors");
            log_notice_q("Exiting");
            exit(EXIT_FAILURE);
            /*NOTREACHED*/
        }

        /*
         * Inform the "filel" module of the shared memory segment
         */
        if (shmid != -1 && semid != -1)
        {
            set_shared_space(shmid, semid, queue_size);
        }

        /*
         * Compile the pattern.
         */
        if (re_isPathological(spec.pattern))
        {
                log_error_q("Adjusting pathological regular-expression: \"%s\"",
                    spec.pattern);
                re_vetSpec(spec.pattern);
        }
        status = regcomp(&spec.rgx, spec.pattern, REG_EXTENDED|REG_NOSUB);
        if(status != 0)
        {
                log_error_q("Can't compile regular expression \"%s\"",
                        spec.pattern);
                log_notice_q("Exiting");
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }

        /*
         * register exit handler
         */
        if(atexit(cleanup) != 0)
        {
                log_syserr_q("atexit");
                log_notice_q("Exiting");
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }

        /*
         * set up signal handlers
         */
        set_sigactions();

        /*
         * Read in (compile) the configuration file.  We do this first so
         * its syntax may be checked without opening a product queue.
         */
        if ((status = readPatFile(conffilename)) < 0) {
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }
        else if (status == 0) {
            log_notice_q("Configuration-file \"%s\" has no entries. "
                "You should probably not start this program instead.",
                conffilename);
        }

        /*
         * Open the product queue
         */
        status = pq_open(pqfname, PQ_READONLY, &pq);
        if(status)
        {
                if (PQ_CORRUPT == status) {
                    log_error_q("The product-queue \"%s\" is inconsistent\n",
                            pqfname);
                }
                else {
                    log_error_q("pq_open failed: %s: %s\n",
                            pqfname, strerror(status));
                }
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }

        if(toffset != TOFFSET_NONE) {
            /*
             * Filter and queue position set by "toffset".
             */
            clss.from.tv_sec -= toffset;
            pq_cset(pq, &clss.from);
        }
        else {
            bool       startAtTailEnd = true;
            timestampt insertTime;

            clss.from = TS_ZERO;

            /*
             * Try getting the insertion-time of the last,
             * successfully-processed data-product from the previous session.
             */
            status = stateRead(&insertTime);

            if (status) {
                log_warning_q("Couldn't get insertion-time of last-processed "
                        "data-product from previous session");
            }
            else {
                timestampt now;
                (void)set_timestamp(&now);

                if (tvCmp(now, insertTime, <)) {
                    log_warning_q("Time of last-processed data-product from previous "
                            "session is in the future");
                }
                else {
                    char buf[80];
                    (void)strftime(buf, sizeof(buf), "%Y-%m-%d %T",
                        gmtime(&insertTime.tv_sec));
                    log_notice_q("Starting from insertion-time %s.%06lu UTC", buf,
                        (unsigned long)insertTime.tv_usec);

                    pq_cset(pq, &insertTime);
                    startAtTailEnd = false;
                }
            }

            if (startAtTailEnd) {
                log_notice_q("Starting at tail-end of product-queue");
                (void)pq_last(pq, &clss, NULL);
            }
        }
Exemple #11
0
/*
 * Returns:
 *      0               Success
 *      SYSTEM_ERROR    O/S failure. "log_add()" called.
 *      LP_TIMEDOUT     The RPC call timed-out. "log_add()" called.
 *      LP_RPC_ERROR    RPC error. "log_add()" called.
 *      LP_LDM_ERROR    LDM error. "log_add()" called.
 */
int
main(
    int         ac,
    char*       av[])
{
    char            myname[_POSIX_HOST_NAME_MAX];
    char*           progname = av[0];
    prod_class_t    clss;
    prod_spec       spec;
    int             seq_start = 0;
    int             status;
    ErrorObj*       error;
    unsigned        remotePort = LDM_PORT;

    /*
     * Set up error logging
     */
    (void)log_init(progname);

    remote = "localhost";

    (void)set_timestamp(&clss.from);
    clss.to = TS_ENDT;
    clss.psa.psa_len = 1;
    clss.psa.psa_val = &spec;
    spec.feedtype = DEFAULT_FEEDTYPE;
    spec.pattern = ".*";

    {
        extern int optind;
        extern char *optarg;
        int ch;

        while ((ch = getopt(ac, av, "vxl:h:f:P:s:")) != EOF)
            switch (ch) {
            case 'v':
                if (!log_is_enabled_info)
                    (void)log_set_level(LOG_LEVEL_INFO);
                break;
            case 'x':
                (void)log_set_level(LOG_LEVEL_DEBUG);
                break;
            case 'l':
                (void)log_set_destination(optarg);
                break;
            case 'h':
                remote = optarg;
                break;
            case 'f':
                spec.feedtype = atofeedtypet(optarg);
                if(spec.feedtype == NONE)
                {
                    fprintf(stderr, "Unknown feedtype \"%s\"\n",
                            optarg);
                        usage(progname);        
                }
                break;
            case 'P': {
                char*       suffix = "";
                long        port;

                errno = 0;
                port = strtol(optarg, &suffix, 0);

                if (0 != errno || 0 != *suffix ||
                    0 >= port || 0xffff < port) {

                    (void)fprintf(stderr, "%s: invalid port %s\n",
                         av[0], optarg);
                    usage(av[0]);   
                }

                remotePort = (unsigned)port;

                break;
            }
            case 's':
                seq_start = atoi(optarg);
                break;
            case '?':
                usage(progname);
                break;
            }

        ac -= optind; av += optind;

        if(ac < 1) usage(progname);
    }

    /*
     * Register the exit handler
     */
    if(atexit(cleanup) != 0)
    {
        log_syserr_q("atexit");
        exit(SYSTEM_ERROR);
    }

    /*
     * Set up signal handlers
     */
    set_sigactions();

    (void) strncpy(myname, ghostname(), sizeof(myname));
    myname[sizeof(myname)-1] = 0;

    (void)exitIfDone(INTERRUPTED);

    /*
     * Connect to the LDM.
     */
    status = lp_new(remote, &ldmProxy);

    if (0 != status) {
        log_flush_error();
        status = (LP_SYSTEM == status)
            ? SYSTEM_ERROR
            : CONNECTION_ABORTED;
    }
    else {
        log_debug("version %u", lp_version(ldmProxy));

        status = ldmsend(ldmProxy, &clss, myname, seq_start, ac, av);

        if (0 != status)
            log_flush_error();

        lp_free(ldmProxy);
        ldmProxy = NULL;
    }                                       /* "ldmProxy" allocated */

    return status; 
}
Exemple #12
0
/*
 * Sends a list of files to the LDM as data-products.
 *
 * Arguments:
 *      ldmProxy        The LDM proxy data-structure.
 *      offer           The description of the class of data-products that this
 *                      process is willing to send.
 *      origin          The identifier of the host that created the
 *                      data-products (typically the host running this program).
 *      seq_start       The starting value of the data-product sequence number.
 *      nfiles          The number of files to send.
 *      filenames       The pathnames of the files to send.
 *
 * Returns:
 *      0                       Success.
 *      SYSTEM_ERROR            O/S failure. "log_add()" called.
 *      CONNECTION_ABORTED      The connection was aborted. "log_add()"        *                              called.
 */
static int
ldmsend(
    LdmProxy*           ldmProxy,
    prod_class_t*       offer,
    char*               origin,
    int                 seq_start,
    int                 nfiles,
    char*               filenames[])
{
    int                 status = 0;
    char*               filename;
    int                 fd;
    struct stat         statb;
    prod_info           info;
    MD5_CTX*            md5ctxp = NULL;
    prod_class_t*       want;

    /*
     * Allocate an MD5 context
     */
    md5ctxp = new_MD5_CTX();
    if (md5ctxp == NULL)
    {
        log_syserr_q("new_md5_CTX failed");
        return SYSTEM_ERROR;
    }

    status = lp_hiya(ldmProxy, offer, &want);

    if (status != 0) {
        status = CONNECTION_ABORTED;
    }
    else {
        /* These members are constant over the loop. */
        info.origin = origin;
        info.feedtype = offer->psa.psa_val->feedtype;

        for (info.seqno = seq_start; exitIfDone(1) && nfiles > 0;
                filenames++, nfiles--, info.seqno++) {
            filename = *filenames;
            info.ident = filename;
            /*
             * ?? This could be the creation time of the file.
             */
            (void) set_timestamp(&info.arrival);

            /*
             * Checks 'arrival', 'feedtype', and 'ident'
             * against what the other guy has said he wants.
             */
            if (!prodInClass(offer, &info)) {
                log_info_q("Not going to send %s", filename);
                continue;       
            }
            if (!prodInClass(want, &info)) {
                log_info_q("%s doesn't want %s", lp_host(ldmProxy), filename);
                continue;       
            }

            fd = open(filename, O_RDONLY, 0);
            if (fd == -1) {
                log_syserr_q("open: %s", filename);
                continue;
            }

            if (fstat(fd, &statb) == -1) {
                log_syserr_q("fstat: %s", filename);
                (void) close(fd);
                continue;
            }

            log_info_q("Sending %s, %d bytes", filename, statb.st_size);
            
            /* These members, and seqno, vary over the loop. */
            if (fd_md5(md5ctxp, fd, statb.st_size, info.signature) != 0) {
                (void) close(fd);
                continue;
            }
            if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
                log_syserr_q("rewind: %s", filename);
                (void) close(fd);
                continue;
            }

            info.sz = (u_int)statb.st_size;

            (void)exitIfDone(1);

            status = send_product(ldmProxy, fd, &info);

            (void) close(fd);

            if (0 != status) {
                log_add("Couldn't send file \"%s\" to LDM", filename);
                break;
            }
        }                                       /* file loop */

        if (lp_flush(ldmProxy))
            log_add("Couldn't flush connection");

        free_prod_class(want);
    }                                           /* HIYA succeeded */

    free_MD5_CTX(md5ctxp);  
    return status;
}
Exemple #13
0
/*ARGSUSED0*/
static void myStartElement(
    void*           user_data,
    const xmlChar*  name,
    const xmlChar** attrs)
{
    switch (currState) {

    case START:
        if (xmlStrcmp(name, rootEltName) == 0) {
            currState = IN_ROOT_ELT;
        }
        else {
            log_error_q("Root element \"%s\" is not \"%s\"",  name,
                    rootEltName);
            currState = ERROR;
        }
        break;

    case IN_ROOT_ELT:
        if (xmlStrcmp(name, feedEltName) != 0) {
            prevState = currState;
            currState = UNKNOWN;
            unknownLevel = 1;
        }
        else {
            const xmlChar** nameValuePair = attrs;
            for (; *nameValuePair != NULL; nameValuePair += 2) {
                const xmlChar* attName = nameValuePair[0];

                if (xmlStrcmp(attName, typeAttName) == 0) {
                    if (strfeedtypet((const char*)nameValuePair[1], &feedType)
                        != FEEDTYPE_OK) {

                        log_error_q("Invalid feed type: \"%s\"",
                                nameValuePair[1]);
                        currState = ERROR;
                    }
                }
                else if (xmlStrcmp(attName, idAttName) == 0) {
                    prodId = strdup((char*)nameValuePair[1]);

                    if (prodId == NULL) {
                        log_syserr_q( "Couldn't duplicate product ID: \"%s\"",
                                nameValuePair[1]);
                        currState = ERROR;
                    }
                }
                else if (xmlStrcmp(attName, sizeAttName) == 0) {
                    if (sscanf((const char*)nameValuePair[1], "%u", &prodSize)
                        != 1) {

                        log_syserr_q("Invalid product size: \"%s\"",
                                nameValuePair[1]);
                        currState = ERROR;
                    }
                }
                else if (xmlStrcmp(attName, delayAttName) == 0) {
                    if (sscanf((const char*)nameValuePair[1], "%u", &delay)
                        != 1) {

                        log_syserr_q("Invalid delay time: \"%s\"",
                                nameValuePair[1]);
                        currState = ERROR;
                    }
                }
                else {
                    log_error_q("Invalid attribute: \"%s\"", attName);
                    currState = ERROR;
                }
            }
        }
        break;

    case UNKNOWN:
        ++unknownLevel;
        break;
    }
}
Exemple #14
0
/**
 * Feeds or notifies a downstream LDM. This function returns either NULL or a
 * reply to be sent to the downstream LDM (e.g., a RECLASS message) or
 * terminates this process (hopefully after sending some data).
 * 
 * @param xprt          [in/out] Pointer to server-side transport handle.
 * @param want          [in] Pointer to subscription by downstream LDM.
 *                      May contain a "signature" product-specification.
 * @param isNotifier    [in] Whether or not the upstream LDM is a feeder or a
 *                      notifier.
 * @param maxHereis     Maximum HEREIS size parameter. Ignored if "isNotifier"
 *                      is true.
 * @return              The reply for the downstream LDM or NULL if no reply
 *                      should be made.
 */
static fornme_reply_t*
feed_or_notify(
    SVCXPRT* const              xprt,
    const prod_class_t* const   want,
    const int                   isNotifier,
    const max_hereis_t          maxHereis)
{
    struct sockaddr_in      downAddr = *svc_getcaller(xprt);
    ErrorObj*               errObj;
    int                     status;
    char*                   downName = NULL;
    prod_class_t*           origSub = NULL;
    prod_class_t*           allowSub = NULL;
    const signaturet*       signature = NULL;
    UpFilter*               upFilter = NULL;
    fornme_reply_t*         reply = NULL;
    int                     isPrimary;
    static fornme_reply_t   theReply;
    static prod_class_t*    uldbSub = NULL;

    /*
     * Clean-up from a (possibly) previous invocation
     */
    (void)memset(&theReply, 0, sizeof(theReply));
    if (uldbSub != NULL) {
        free_prod_class(uldbSub);
        uldbSub = NULL;
    }

    downName = strdup(hostbyaddr(&downAddr));
    if (NULL == downName) {
        log_error_q("Couldn't duplicate downstream host name: \"%s\"",
                hostbyaddr(&downAddr));
        svcerr_systemerr(xprt);
        goto return_or_exit;
    }

    log_set_upstream_id(downName, !isNotifier);

    /*
     * Remove any "signature" specification from the subscription.
     */
    if ((errObj = separateProductClass(want, &origSub, &signature)) != NULL) {
        err_log_and_free(errObj, ERR_FAILURE);
        svcerr_systemerr(xprt);
        goto free_down_name;
    }

    /*
     * Get the upstream filter
     */
    errObj = lcf_getUpstreamFilter(downName, &downAddr.sin_addr, origSub,
            &upFilter);
    if (errObj) {
        err_log_and_free(ERR_NEW(0, errObj,
                "Couldn't get \"upstream\" filter"), ERR_FAILURE);
        svcerr_systemerr(xprt);
        goto free_orig_sub;
    }
    if (NULL == upFilter) {
        err_log_and_free(ERR_NEW1(0, NULL,
                "Upstream filter prevents data-transfer: %s",
                s_prod_class(NULL, 0, origSub)), ERR_FAILURE);
        svcerr_weakauth(xprt);
        goto free_orig_sub;
    }

    /* TODO: adjust time? */

    /*
     * Reduce the subscription according to what the downstream host is allowed
     * to receive.
     */
    status = lcf_reduceToAllowed(downName, &downAddr.sin_addr, origSub,
            &allowSub);
    if (status == ENOMEM) {
        log_syserr_q("Couldn't compute wanted/allowed product intersection");
        svcerr_systemerr(xprt);
        goto free_up_filter;
    }
    if (status == EINVAL) {
        log_warning_q("Invalid pattern in product-class: %s",
                s_prod_class(NULL, 0, origSub));
        theReply.code = BADPATTERN;
        reply = &theReply;
        goto free_up_filter;
    }
    assert(status == 0);
    (void) logIfReduced(origSub, allowSub, "ALLOW entries");

    /*
     * Reduce the subscription according to existing subscriptions from the
     * same downstream host and, if `isAntiDosEnabled()` returns `true`,
     * terminate every previously-existing upstream LDM process that's feeding
     * (not notifying) a subset of the subscription to the same IP address.
     *
     * The following relies on atexit()-registered cleanup for removal of the
     * entry from the upstream LDM database.
     */
    isPrimary = maxHereis > UINT_MAX / 2;
    status = uldb_addProcess(getpid(), 6, &downAddr, allowSub, &uldbSub,
            isNotifier, isPrimary);
    if (status) {
        log_error_q("Couldn't add this process to the upstream LDM database");
        svcerr_systemerr(xprt);
        goto free_allow_sub;
    }
    (void) logIfReduced(allowSub, uldbSub, "existing subscriptions");

    /*
     * Send a RECLASS reply to the downstream LDM if appropriate.
     */
    if (!clss_eq(origSub, uldbSub)) {
        theReply.code = RECLASS;

        if (0 < uldbSub->psa.psa_len) {
            /*
             * The downstream LDM is allowed less than it requested and was
             * entered into the upstream LDM database.
             */
            (void)uldb_remove(getpid()); /* maybe next time */

            theReply.fornme_reply_t_u.prod_class = uldbSub;
        }
        else {
            /*
             * The downstream LDM isn't allowed anything and wasn't entered
             * into the upstream LDM database.
             */
            static prod_class noSub = { { 0, 0 }, /* TS_ZERO */
                { 0, 0 }, /* TS_ZERO */ { 0, (prod_spec *) NULL } };

            theReply.fornme_reply_t_u.prod_class = &noSub;
        }

        reply = &theReply;

        goto free_allow_sub;
    }

    /*
     * Reply to the downstream LDM that the subscription will be honored.
     */
    theReply.code = OK;
    theReply.fornme_reply_t_u.id = (unsigned) getpid();
    if (!svc_sendreply(xprt, (xdrproc_t)xdr_fornme_reply_t,
            (caddr_t)&theReply)) {
        log_error_q("svc_sendreply(...) failure");
        svcerr_systemerr(xprt);
        goto free_allow_sub;
    }

    /*
     * Wait a second before sending anything to the downstream LDM.
     */
    (void) sleep(1);

    status = isNotifier
            ? up6_new_notifier(xprt->xp_sock, downName, &downAddr, uldbSub,
                    signature, getQueuePath(), interval, upFilter)
            : up6_new_feeder(xprt->xp_sock, downName, &downAddr, uldbSub,
                    signature, getQueuePath(), interval, upFilter,
                    isPrimary);

    svc_destroy(xprt); /* closes the socket */
    exit(status);

    /*
     * Reply and error handling:
     */
    free_allow_sub:
        free_prod_class(allowSub);

    free_up_filter:
        upFilter_free(upFilter);

    free_orig_sub:
        free_prod_class(origSub);

    free_down_name:
        free(downName);

    return_or_exit:
        return reply;
}
Exemple #15
0
int main(
        int ac,
        char *av[]
)
{
        const char* const progname = basename(av[0]);
        int useProductID = FALSE;
        int signatureFromId = FALSE;
        char *productID = NULL;
        int multipleFiles = FALSE;
        char identifier[KEYSIZE];
        int status;
        int seq_start = 0;
        enum ExitCode {
            exit_success = 0,   /* all files inserted successfully */
            exit_system = 1,    /* operating-system failure */
            exit_pq_open = 2,   /* couldn't open product-queue */
            exit_infile = 3,    /* couldn't process input file */
            exit_dup = 4,       /* input-file already in product-queue */
            exit_md5 = 6        /* couldn't initialize MD5 processing */
        } exitCode = exit_success;

        (void)log_init(progname);

#if !USE_MMAP
        pqeIndex = PQE_NONE;
#endif

        {
            extern int optind;
            extern int opterr;
            extern char *optarg;
            int ch;

            opterr = 0; /* Suppress getopt(3) error messages */

            while ((ch = getopt(ac, av, ":ivxl:q:f:s:p:")) != EOF)
                    switch (ch) {
                    case 'i':
                            signatureFromId = 1;
                            break;
                    case 'v':
                            if (!log_is_enabled_info)
                                (void)log_set_level(LOG_LEVEL_INFO);
                            break;
                    case 'x':
                            (void)log_set_level(LOG_LEVEL_DEBUG);
                            break;
                    case 'l':
                            (void)log_set_destination(optarg);
                            break;
                    case 'q':
                            setQueuePath(optarg);
                            break;
                    case 's':
                            seq_start = atoi(optarg);
                            break;
                    case 'f':
                            feedtype = atofeedtypet(optarg);
                            if(feedtype == NONE)
                            {
                                fprintf(stderr, "Unknown feedtype \"%s\"\n", optarg);
                                    usage(progname);
                            }
                            break;
                    case 'p':
                            useProductID = TRUE;
                            productID = optarg;
                            break;
                    case ':': {
                        log_add("Option \"-%c\" requires an operand", optopt);
                        usage(progname);
                    }
                    /* no break */
                    default:
                        log_add("Unknown option: \"%c\"", optopt);
                        usage(progname);
                        /* no break */
                    }

            ac -= optind; av += optind ;

            if(ac < 1) usage(progname);
            }

        const char* const       pqfname = getQueuePath();

        /*
         * register exit handler
         */
        if(atexit(cleanup) != 0)
        {
                log_syserr_q("atexit");
                exit(exit_system);
        }

        /*
         * set up signal handlers
         */
        set_sigactions();

        /*
         * who am i, anyway
         */
        (void) strncpy(myname, ghostname(), sizeof(myname));
        myname[sizeof(myname)-1] = 0;

        /*
         * open the product queue
         */
        if(status = pq_open(pqfname, PQ_DEFAULT, &pq))
        {
                if (PQ_CORRUPT == status) {
                    log_error_q("The product-queue \"%s\" is inconsistent\n",
                            pqfname);
                }
                else {
                    log_error_q("pq_open: \"%s\" failed: %s",
                            pqfname, status > 0 ? strerror(status) :
                                            "Internal error");
                }
                exit(exit_pq_open);
        }


        {
        char *filename;
        int fd;
        struct stat statb;
        product prod;
        MD5_CTX *md5ctxp = NULL;

        /*
         * Allocate an MD5 context
         */
        md5ctxp = new_MD5_CTX();
        if(md5ctxp == NULL)
        {
                log_syserr_q("new_md5_CTX failed");
                exit(exit_md5);
        }


        /* These members are constant over the loop. */
        prod.info.origin = myname;
        prod.info.feedtype = feedtype;

        if (ac > 1) {
          multipleFiles = TRUE;
        }

        for(prod.info.seqno = seq_start ; ac > 0 ;
                         av++, ac--, prod.info.seqno++)
        {
                filename = *av;

                fd = open(filename, O_RDONLY, 0);
                if(fd == -1)
                {
                        log_syserr_q("open: %s", filename);
                        exitCode = exit_infile;
                        continue;
                }

                if( fstat(fd, &statb) == -1) 
                {
                        log_syserr_q("fstat: %s", filename);
                        (void) close(fd);
                        exitCode = exit_infile;
                        continue;
                }

                /* Determine what to use for product identifier */
                if (useProductID) 
                  {
                    if (multipleFiles) 
                      {
                        sprintf(identifier,"%s.%d", productID, prod.info.seqno);
                        prod.info.ident = identifier;
                      }
                    else
                      prod.info.ident = productID;
                   }
                else
                    prod.info.ident = filename;
                
                prod.info.sz = statb.st_size;
                prod.data = NULL;

                /* These members, and seqno, vary over the loop. */
                status = set_timestamp(&prod.info.arrival);
                if(status != ENOERR) {
                        log_syserr_q("set_timestamp: %s, filename");
                        exitCode = exit_infile;
                        continue;
                }

#if USE_MMAP
                prod.data = mmap(0, prod.info.sz,
                        PROT_READ, MAP_PRIVATE, fd, 0);
                if(prod.data == MAP_FAILED)
                {
                        log_syserr_q("mmap: %s", filename);
                        (void) close(fd);
                        exitCode = exit_infile;
                        continue;
                }

                status = 
                    signatureFromId
                        ? mm_md5(md5ctxp, prod.info.ident,
                            strlen(prod.info.ident), prod.info.signature)
                        : mm_md5(md5ctxp, prod.data, prod.info.sz,
                            prod.info.signature);

                (void)exitIfDone(1);

                if (status != 0) {
                    log_syserr_q("mm_md5: %s", filename);
                    (void) munmap(prod.data, prod.info.sz);
                    (void) close(fd);
                    exitCode = exit_infile;
                    continue;
                }

                /* These members, and seqno, vary over the loop. */
                status = set_timestamp(&prod.info.arrival);
                if(status != ENOERR) {
                        log_syserr_q("set_timestamp: %s, filename");
                        exitCode = exit_infile;
                        continue;
                }

                /*
                 * Do the deed
                 */
                status = pq_insert(pq, &prod);

                switch (status) {
                case ENOERR:
                    /* no error */
                    if(log_is_enabled_info)
                        log_info_q("%s", s_prod_info(NULL, 0, &prod.info,
                            log_is_enabled_debug)) ;
                    break;
                case PQUEUE_DUP:
                    log_error_q("Product already in queue: %s",
                        s_prod_info(NULL, 0, &prod.info, 1));
                    exitCode = exit_dup;
                    break;
                case PQUEUE_BIG:
                    log_error_q("Product too big for queue: %s",
                        s_prod_info(NULL, 0, &prod.info, 1));
                    exitCode = exit_infile;
                    break;
                case ENOMEM:
                    log_error_q("queue full?");
                    exitCode = exit_system;
                    break;  
                case EINTR:
#if defined(EDEADLOCK) && EDEADLOCK != EDEADLK
                case EDEADLOCK:
                    /*FALLTHROUGH*/
#endif
                case EDEADLK:
                    /* TODO: retry ? */
                    /*FALLTHROUGH*/
                default:
                    log_error_q("pq_insert: %s", status > 0
                        ? strerror(status) : "Internal error");
                    break;
                }

                (void) munmap(prod.data, prod.info.sz);
#else // USE_MMAP above; !USE_MMAP below
                status = 
                    signatureFromId
                        ? mm_md5(md5ctxp, prod.info.ident,
                            strlen(prod.info.ident), prod.info.signature)
                        : fd_md5(md5ctxp, fd, statb.st_size,
                            prod.info.signature);

                (void)exitIfDone(1);

                if (status != 0) {
                        log_syserr_q("xx_md5: %s", filename);
                        (void) close(fd);
                        exitCode = exit_infile;
                        continue;
                }

                if(lseek(fd, 0, SEEK_SET) == (off_t)-1)
                {
                        log_syserr_q("rewind: %s", filename);
                        (void) close(fd);
                        exitCode = exit_infile;
                        continue;
                }

                pqeIndex = PQE_NONE;
                status = pqe_new(pq, &prod.info, &prod.data, &pqeIndex);

                if(status != ENOERR) {
                    log_syserr_q("pqe_new: %s", filename);
                    exitCode = exit_infile;
                }
                else {
                    ssize_t     nread = read(fd, prod.data, prod.info.sz);

                    (void)exitIfDone(1);

                    if (nread != prod.info.sz) {
                        log_syserr_q("read %s %u", filename, prod.info.sz);
                        status = EIO;
                    }
                    else {
                        status = pqe_insert(pq, pqeIndex);
                        pqeIndex = PQE_NONE;

                        switch (status) {
                        case ENOERR:
                            /* no error */
                            if(ulogIsVerbose())
                                log_info_q("%s", s_prod_info(NULL, 0, &prod.info,
                                    log_is_enabled_debug)) ;
                            break;
                        case PQUEUE_DUP:
                            log_error_q("Product already in queue: %s",
                                s_prod_info(NULL, 0, &prod.info, 1));
                            exitCode = exit_dup;
                            break;
                        case ENOMEM:
                            log_error_q("queue full?");
                            break;  
                        case EINTR:
#if defined(EDEADLOCK) && EDEADLOCK != EDEADLK
                        case EDEADLOCK:
                            /*FALLTHROUGH*/
#endif
                        case EDEADLK:
                            /* TODO: retry ? */
                            /*FALLTHROUGH*/
                        default:
                            log_error_q("pq_insert: %s", status > 0
                                ? strerror(status) : "Internal error");
                        }
                    }                   /* data read into `pqeIndex` region */

                    if (status != ENOERR) {
                        (void)pqe_discard(pq, pqeIndex);
                        pqeIndex = PQE_NONE;
                    }
                }                       /* `pqeIndex` region allocated */

#endif
                (void) close(fd);
        }                               /* input-file loop */

        free_MD5_CTX(md5ctxp);  
        }                               /* code block */

        exit(exitCode);
}
Exemple #16
0
hiya_reply_t*
hiya_6_svc(
        prod_class_t *offered,
        struct svc_req *rqstp)
{
    const char* const pqfname = getQueuePath();
    static hiya_reply_t reply;
    SVCXPRT * const xprt = rqstp->rq_xprt;
    struct sockaddr_in *upAddr = (struct sockaddr_in*) svc_getcaller(xprt);
    const char *upName = hostbyaddr(upAddr);
    int error;
    int isPrimary;
    unsigned int maxHereis;
    static prod_class_t *accept;

    /*
     * Open the product-queue for writing.  It will be closed by cleanup()
     * during process termination.
     */
    if (pq) {
        (void) pq_close(pq);
        pq = NULL;
    }
    error = pq_open(pqfname, PQ_DEFAULT, &pq);
    if (error) {
        err_log_and_free(ERR_NEW2(error, NULL,
                "Couldn't open product-queue \"%s\" for writing: %s",
                pqfname,
                PQ_CORRUPT == error
                ? "The product-queue is inconsistent"
                : strerror(error)), ERR_FAILURE);
        svcerr_systemerr(xprt);
        svc_destroy(xprt);
        exit(error);
    }

    /* else */

    error = down6_init(upName, upAddr, pqfname, pq);
    if (error) {
        log_error_q("Couldn't initialize downstream LDM");
        svcerr_systemerr(xprt);
        svc_destroy(xprt);
        exit(error);
    }
    else {
        log_info_q("Downstream LDM initialized");
    }

    /*
     * The previous "accept" is freed here -- rather than freeing the
     * soon-to-be-allocated "accept" at the end of its block -- because it can
     * be used in the reply.
     */
    if (accept) {
        free_prod_class(accept); /* NULL safe */
        accept = NULL;
    }

    error = lcf_reduceToAcceptable(upName, inet_ntoa(upAddr->sin_addr), offered,
            &accept, &isPrimary);

    maxHereis = isPrimary ? UINT_MAX : 0;

    if (error) {
        log_syserr_q("Couldn't validate HIYA");
        svcerr_systemerr(xprt);
        svc_destroy(xprt);
        exit(error);
    }
    else {
        if (log_is_enabled_debug)
            log_debug("intersection: %s", s_prod_class(NULL, 0, accept));

        if (accept->psa.psa_len == 0) {
            log_warning_q("Empty intersection of HIYA offer from %s (%s) and ACCEPT "
                    "entries", upName, s_prod_class(NULL, 0, offered));
            svcerr_weakauth(xprt);
            svc_destroy(xprt);
            exit(0);
        }
        else {
            error = down6_set_prod_class(accept);

            if (error) {
                if (DOWN6_SYSTEM_ERROR == error) {
                    log_syserr_q("Couldn't set product class: %s",
                            s_prod_class(NULL, 0, accept));
                }
                else {
                    log_error_q("Couldn't set product class: %s",
                            s_prod_class(NULL, 0, accept));
                }

                svcerr_systemerr(xprt);
                svc_destroy(xprt);
                exit(EXIT_FAILURE);
            }

            /* else */

            if (clss_eq(offered, accept)) {
                log_notice_q("hiya6: %s", s_prod_class(NULL, 0, offered));

                reply.code = OK;
                reply.hiya_reply_t_u.max_hereis = maxHereis;
            }
            else {
                if (log_is_enabled_info) {
                    char off[512];
                    char acc[512];

                    (void) s_prod_class(off, sizeof(off), offered), (void) s_prod_class(
                            acc, sizeof(acc), accept);

                    log_info_q("hiya6: RECLASS: %s -> %s", off, acc);
                }

                reply.code = RECLASS;
                reply.hiya_reply_t_u.feedPar.prod_class = accept;
                reply.hiya_reply_t_u.feedPar.max_hereis = maxHereis;
            }
        } /* product-intersection != empty set */
    } /* successful acl_check_hiya() */

    return &reply;
}
Exemple #17
0
/* 
 * Opens the configuration file.  Any previously opened configuration file will
 * be closed.  The ulog(3) facility will be used to log any problems.
 *
 * pathname          The pathname of the file. (in)
 *
 * Returns:
 *   pq.h:ENOERR     if success.
 *   errno.h:ENOMEM  if out of memory.
 *   errno.h:EINVAL  if the pathname is NULL or if the configuration file was 
 *                   invalid.
 *   (else)          <errno.h> error code.
 */
int cfOpen(const char* pathname)
{
    int              status;

    if (pathname == NULL) {
        log_error_q("NULL pathname");
        status = EINVAL;
    }
    else {
        if (currState != CLOSED)
            cfClose();

        md5 = new_MD5_CTX();

        if (saxer.startDocument != myStartDocument) {
            saxer.startDocument = myStartDocument;
            saxer.startElement = myStartElement;
            saxer.getEntity = myGetEntity;
            saxer.characters = myCharacters;
            saxer.endElement = myEndElement;
            saxer.endDocument = myEndDocument;
            saxer.warning = xmlWarning;
            saxer.error = xmlError;
            saxer.fatalError = xmlError;
        }

        (void)xmlSAXUserParseFile(&saxer, NULL, pathname);

        if (currState != READY) {
            cfClose();
            status = EINVAL;
        }
        else {
            prodData = realloc(prodData, prodSize);

            if (prodData == NULL) {
                log_syserr_q("Couldn't allocate %u bytes for product data",
                        prodSize);
                status = ENOMEM;
            }
            else {
                (void)memset(prodData, 'x', prodSize);

                prodInfo.origin = (char*)ghostname();
                prodInfo.feedtype = feedType;
                prodInfo.ident = prodId;
                prodInfo.sz = prodSize;
                prodXdrLen = xlen_prod_i(&prodInfo);
                prodXdrBuf = realloc(prodXdrBuf, prodXdrLen);

                if (prodXdrBuf == NULL) {
                    log_syserr_q("Couldn't allocate %lu bytes for product XDR "
                            "buffer", prodXdrLen);
                    status = errno;
                }
                else {
                    prod.data = prodData;
                    status = ENOERR;
                }

                if (status != ENOERR) {
                    free(prodData);
                    prodData = NULL;
                }
            }
        }
    }

    return status;
}