Ejemplo n.º 1
0
/* retry registering inotify watches, using the retry strategy parameters */
static void wait_reg_watches(const char *qpath, const char *rqpath) {
    double slp = WAIT_INIT;

    while (!stop_requested()) {
        if (try_reg_watches(qpath, rqpath)) {
            flog(LOG_DEBUG, "registered watches");
            break;
        }
        else {
            sleepsec(slp);

            slp = (slp * WAIT_MULT);
            if (slp > WAIT_MAX)
                slp = WAIT_MAX;
        }
    }
}
Ejemplo n.º 2
0
/*
  exec run_loop for all correct entries in (r)queue directory
  NOT thread-safe, since readdir_r is unreliable with filenames > NAME_MAX
  (e.g., NTFS + 255 unicode chars get truncated to 256 chars w/o terminating NUL)
*/
static void retry_dir(const char *qtype, const char *qpath, const char *looppath) {
    /* [offsetof(struct dirent, d_name) + fpathconf(fd, _PC_NAME_MAX) + 1] */
    struct dirent *de;
    struct stat   st;
    DIR    *qdir;
    int    fd, run;

    flog(LOG_DEBUG, "retrying %s directories", qtype);

    /* open directory (O_CLOEXEC is implied) */
    if ((qdir = opendir(qpath))) {
        /* get corresponding file descriptor for stat */
        if ((fd = dirfd(qdir)) != -1) {
            for (errno = 0;  !stop_requested()  &&  ((de = readdir(qdir))); ) {
                run = 0;

                /* some filesystems don't support d_type, need to stat entry */
                if (de->d_type == DT_UNKNOWN  &&  is_msgdir(de->d_name)) {
                    if (!fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW))
                        run = S_ISDIR(st.st_mode);
                    else
                        warning("fstat failed");
                }
                else
                    run = (de->d_type == DT_DIR  &&  is_msgdir(de->d_name));

                if (run)
                    run_loop(qtype, de->d_name, looppath);
            }

            if (errno  &&  errno != EINTR)
                warning("reading directory failed");
        }
        else
            warning("dirfd failed");

        /* close directory */
        if (closedir(qdir))
            warning("could not close directory");
    }
    else
        warning("could not open directory");
}
Ejemplo n.º 3
0
bool
play_internal(wav_t *w, audio_t *audio, talking_skull_t *talking_skull, stop_t *stop)
{
    size_t size;
    size_t i;
    bool rc = true;
    unsigned handle;

    assert(w);
    assert(! talking_skull || ! stop);

    size = audio_get_buffer_size(audio);

    if (talking_skull) {
	if (w->servo) {
	    handle = talking_skull_play(talking_skull, w->servo, w->n_servo);
	} else {
	    handle = talking_skull_play(talking_skull, w->audio, w->n_audio);
	}
    }

    for (i = 0; i < w->n_audio && ! stop_requested(stop); i += size) {
	size_t this_size = i + size > w->n_audio ? w->n_audio - i : size;
	if (! audio_play_buffer(audio, &w->audio[i], this_size)) {
	    perror("Error playing sample");
	    rc = false;
	    break;
	}
    }

    if (talking_skull) {
	talking_skull_wait_completion(talking_skull, handle);
    }

    stop_stopped(stop);

    return rc;
}
Ejemplo n.º 4
0
int main() {
    /* using NAME_MAX prevents EINVAL on read() (twice for UTF-16 on NTFS) */
    char   buf[sizeof(struct inotify_event) + NAME_MAX*2 + 1];
    char   *crtpath, *qpath, *rqpath, *looppath, *lsthost, *lstport;
    int    sz, offset, rereg, evqok, retryid;
    struct inotify_event *iev;
    double retrytmout, lastclock;


    /* init logging */
    syslog_init();


    /* extract environment */
    crtpath  = alloc_env(CABLE_CERTS,  "/" CERTS_NAME);
    qpath    = alloc_env(CABLE_QUEUES, "/" QUEUE_NAME);
    rqpath   = alloc_env(CABLE_QUEUES, "/" RQUEUE_NAME);
    looppath = alloc_env(CABLE_HOME,   "/" LOOP_NAME);
    lsthost  = alloc_env(CABLE_HOST,   "");
    lstport  = alloc_env(CABLE_PORT,   "");


    /* initialize rng */
    if (!rand_init())
        warning("failed to initialize RNG");


    /* initialize process accounting */
    if (!init_process_acc())
        warning("failed to initialize process accounting");


    /* initialize webserver */
    if (!init_server(crtpath, qpath, rqpath, lsthost, lstport)) {
        flog(LOG_ERR, "failed to initialize webserver");
        return EXIT_FAILURE;
    }


    /* try to reregister watches as long as no signal caught */
    for (lastclock = getmontime(), retryid = 0;  !stop_requested(); ) {
        /* support empty CABLE_NOLOOP when testing, to act as pure server */
#ifdef TESTING
        if (getenv("CABLE_NOLOOP")) {
            sleepsec(RETRY_TMOUT);
            continue;
        }
#endif

        wait_reg_watches(qpath, rqpath);

        /* read events as long as no signal caught and no unmount / move_self / etc. events read */
        for (rereg = evqok = 0;  !stop_requested()  &&  !rereg; ) {
            /* wait for an event, or timeout (later blocking read() results in error) */
            retrytmout = RETRY_TMOUT + RETRY_TMOUT * (rand_shift() / 2);

            if (wait_read(inotfd, retrytmout - (getmontime() - lastclock))) {
                /* read events (non-blocking), taking care to handle interrupts due to signals */
                if ((sz = read(inotfd, buf, sizeof(buf))) == -1  &&  errno != EINTR) {
                    /* happens buffer is too small (e.g., NTFS + 255 unicode chars) */
                    warning("error while reading from inotify queue");
                    rereg = 1;
                }

                /* process all events in buffer, sz = -1 and 0 are automatically ignored */
                for (offset = 0;  offset < sz  &&  !stop_requested()  &&  !rereg;  evqok = 1) {
                    /* get handler to next event in read buffer, and update offset */
                    iev     = (struct inotify_event*) (buf + offset);
                    offset += sizeof(struct inotify_event) + iev->len;

                    /*
                      IN_IGNORED is triggered by watched directory removal / fs unmount
                      IN_MOVE_SELF is only triggered by move of actual watched directory
                      (i.e., not its parent)
                    */
                    if ((iev->mask & (IN_IGNORED | IN_UNMOUNT | IN_Q_OVERFLOW | IN_MOVE_SELF)))
                        rereg = 1;

                    /* ignore non-subdirectory events, and events with incorrect name */
                    else if (iev->len > 0  &&  (iev->mask & IN_ISDIR)  &&  is_msgdir(iev->name)) {
                        assert(iev->wd == inotqwd  ||  iev->wd == inotrqwd);
                        if (iev->wd == inotqwd  ||  iev->wd == inotrqwd) {
                            /* stop can be indicated here (while waiting for less processes) */
                            const char *qtype = (iev->wd == inotqwd) ? QUEUE_NAME : RQUEUE_NAME;
                            run_loop(qtype, iev->name, looppath);
                        }
                        else
                            flog(LOG_WARNING, "unknown watch descriptor");
                    }
                }
            }

            /*
              if sufficient time passed since last retries, retry again
            */
            if (!stop_requested()  &&  getmontime() - lastclock >= retrytmout) {
                /* alternate between queue dirs to prevent lock starvation on self-send */
                if ((retryid ^= 1))
                    retry_dir(QUEUE_NAME,  qpath,  looppath);
                else
                    retry_dir(RQUEUE_NAME, rqpath, looppath);

                lastclock = getmontime();

                /* inotify is apparently unreliable on fuse, so reregister when no events */
                if (!evqok)
                    rereg = 1;
                evqok = 0;
            }
        }
    }


    unreg_watches();

    if (!shutdown_server())
        flog(LOG_WARNING, "failed to shutdown webserver");

    dealloc_env(lstport);
    dealloc_env(lsthost);
    dealloc_env(looppath);
    dealloc_env(rqpath);
    dealloc_env(qpath);
    dealloc_env(crtpath);

    flog(LOG_INFO, "exiting");
    closelog();

    return EXIT_SUCCESS;
}