Esempio n. 1
0
int
load_carousel(char* paramDir, struct carousel *car, int cache_size)
{
    int result = 3;

    int processed;
    int index;

    uint32_t prev_transactionId = 0;

    int completed_modules;
    int i = 0;

    unsigned char table[MAX_TABLE_LEN];

    /* no modules yet */
    car->nmodules = 0;
    car->modules = NULL;

    /* tables cached */
    unsigned char* used_slot = safe_malloc(sizeof(unsigned char) * cache_size);
    unsigned char* cached = safe_malloc(MAX_TABLE_LEN * cache_size);
    memset(used_slot, 0, cache_size);

    setbuf(stdout, NULL);

    /* see what the next DSMCC table is */
    do
    {
        struct dsmccMessageHeader *dsmcc;


        if (!car->completed) {
            if(read_dsmcc_tables(car, table) < 0) {
                fatal("Unable to read PID");
                result = 1; // timeout
                car->stop = 1;
            }
        } else { // dsmcc can update itself, keep on reading for dii/dsi changes until we get a complete file system of the same version
            if(read_dsi_dii_tables(car, table) < 0) {
                fatal("Unable to read PID");
                result = 1; // timeout
                car->stop = 1;
            }
        }
        if (!car->stop) {
            dsmcc = (struct dsmccMessageHeader *) &table[8];
            if(dsmcc->protocolDiscriminator == DSMCC_PROTOCOL && dsmcc->dsmccType == DSMCC_TYPE_DOWNLOAD)
            {
                if(ntohs(dsmcc->messageId) == DSMCC_MSGID_DII) {

                    processed = process_dii(car, (struct DownloadInfoIndication *) dsmccMessage(dsmcc), ntohl(dsmcc->transactionId));

                    // verbose2("prev: %d, car_modules: %d, car_id: %d", prev_nmodules, car->nmodules, car->carousel_id);
                    // verbose2("transaction_id: %d, prev_transactionId: %d", dsmcc->transactionId, prev_transactionId);

                    if (prev_transactionId != 0 && dsmcc->transactionId != prev_transactionId) {
                        // carousel probably restarted, return 4
                        result = 4;
                        car->stop = 1;
                        // verbose2("endara");
                    }

                    prev_transactionId = dsmcc->transactionId;

                    if (processed) {
                        verbose("Checking cached tables");

                        unsigned char* cached_table;
                        for (index = 0; index < cache_size; index++) {
                            if (used_slot[index] == 1) {
                                cached_table = cached + (index * MAX_TABLE_LEN);
                                dsmcc = (struct dsmccMessageHeader *) &cached_table[8];
                                processed = process_ddb(paramDir, car, (struct DownloadDataBlock *) dsmccMessage(dsmcc), ntohl(dsmcc->transactionId), DDB_blockDataLength(dsmcc));
                                if (processed) {
                                    verbose("DDB processed from cache index: %d", index);
                                    used_slot[index] = 0;
                                }
                            }
                        }
                        car->completed = 0;
                    } else if (car->nmodules > 0) {
                        verbose("Check if all modules are completed, modules number is %d", car->nmodules);
                        completed_modules = 0;
                        for (i = 0; i < car->nmodules; i++) {
                            if ((car->modules[i]).blocks_left == 0) {
                                completed_modules++;
                            }
                            verbose("module id %d, blocks_left %d", (car->modules[i]).module_id, (car->modules[i]).blocks_left);
                        }

                        /* send progress to stdout */
                        verbose2("completed: %d%%", (completed_modules * 100) / car->nmodules);

                        /* remove this to make it run endless */
                        if (completed_modules == car->nmodules) {
                            car->completed = 1;
                            car->stop = true;
                            verbose2("carousels completed, check dii update");
                        }
                    }

                } else if(ntohs(dsmcc->messageId) == DSMCC_MSGID_DSI) {

                    process_dsi(paramDir, car, (struct DownloadServerInitiate *) dsmccMessage(dsmcc));

                } else if(ntohs(dsmcc->messageId) == DSMCC_MSGID_DDB) {

                    processed = process_ddb(paramDir, car, (struct DownloadDataBlock *) dsmccMessage(dsmcc), ntohl(dsmcc->transactionId), DDB_blockDataLength(dsmcc));
                    if (!processed) {
                        for (index = 0; index < cache_size; index++) {
                            if (used_slot[index] == 0) {
                                verbose("DDB not processed, adding to cache, index is: %d", index);
                                memcpy(cached + (index * MAX_TABLE_LEN), table, MAX_TABLE_LEN);
                                used_slot[index] = 1;
                                index = cache_size;
                            }
                        }
                    }

                } else {

                    error("Unknown DSMCC messageId: 0x%x", ntohs(dsmcc->messageId));

                }
            }
        }
    }
    while(!car->stop);

    verbose("Carousel stopped, doing cleanings ");

    for (i = 0; i < car->npids; i++) {
        if (car->pids[i].filterid >= 0) {
            closePidFiltering(car->pids[i].filterid);
        }
    }

    verbose("descriptor closed ");

    for (i = 0; i < car->nmodules; i++) {
        safe_free(car->modules[i].got_block);
        safe_free(car->modules[i].data);
    }

    verbose("modules block free ");

    safe_free(car->modules);

    verbose("modules free ");

    safe_free(car->pids);

    verbose("pid free ");

    safe_free(used_slot);
    safe_free(cached);

    verbose("cache free ");

    return result;
}
Esempio n. 2
0
int main(int argc, char *argv[])
{
	int out_fd = -1, use_splice = 1, truncate = O_TRUNC, verboseness = 0;
	char *buf = NULL, *dev_path = DEV_PATH, *out_path = NULL;
	int restart_requested, dev_fd, pipe_in, pipe_out, pipe_fd[2];
	ssize_t n, m;
	unsigned int snaplen = 0, buflen = 8192;
	ssize_t (*read_dev)(void);
	ssize_t (*write_out)(void);
	
	struct argp_option options[] = {
		{"append", 'a', 0, 0, "append new records instead of overwriting"},
		{"device", 'd', "DEVICE", 0, "read events from DEVICE (default: " DEV_PATH ")"},
		{"buflen", 'l', "BYTES", 0, "set buffer length; implies -n (default: 8192)"},
		{"no-splice", 'n', 0, 0, "use read()/write() instead of splice"},
		{"quiet", 'q', 0, 0, "decrease verboseness of debug output"},
		{"snaplen", 's', "BYTES", 0, "set maximum packet capture size to BYTES bytes"},
		{"verbose", 'v', 0, 0, "increase verboseness of debug output"},
		{0},
	};

	error_t parse_opt(int key, char *arg, struct argp_state *state)
	{
		switch (key) {
		case 'a':
			truncate = 0;
			break;
		case 'd':
			dev_path = arg;
			break;
		case 'l':
			if (parse_unsigned_int(&buflen, arg))
				argp_error(state, "invalid buflen: %s\n", arg);
			use_splice = 0;
			break;
		case 'n':
			use_splice = 0;
			break;
		case 'q':
			verboseness--;
			break;
		case 's':
			if (parse_unsigned_int(&snaplen, arg))
				argp_error(state, "invalid snaplen: %s\n", arg);
			break;
		case 'v':
			verboseness++;
			break;
		case ARGP_KEY_ARG:
			if (!state->arg_num)
				out_path = arg;
			else
				return ARGP_ERR_UNKNOWN;
			break;
		default:
			return ARGP_ERR_UNKNOWN;
		}
		return 0;
	}

	struct argp argp = {options, parse_opt, "[OUTPUT_FILE]",
			"Read Hone events and write to a file or standard output.",
			NULL, NULL, NULL};

	if (argp_parse(&argp, argc, argv, 0, NULL, NULL))
		err(EX_OSERR, "argp_parse() failed");

	if (verboseness > 0)
		verbose1 = log_stderr;
	if (verboseness > 1)
		verbose2 = log_stderr;
	if (verboseness > 2)
		verbose3 = log_stderr;

	verbose2("Options:\n");
	verbose2("   buffer size: ");
	if (use_splice)
		verbose2("unused\n");
	else
		verbose2("%u\n", buflen);
	verbose2("   input device: %s\n", dev_path);
	verbose2("   output file: %s\n", out_path ?: "<standard output>");
	verbose2("   snaplen: %u\n", snaplen);
	verbose2("   use splice: %s\n", use_splice ? "yes" : "no");
	verbose2("   verbosity level: %d\n", verboseness);

	if (verboseness > 3)
		err(EX_USAGE, "verboseness limit exceeded");

	signal(SIGHUP, sighandler);
	signal(SIGINT, sighandler);
	signal(SIGTERM, sighandler);

	ssize_t splice_read(void)
	{
		return splice(dev_fd, NULL, pipe_in, NULL, 65536, 0);
	}

	ssize_t splice_write(void)
	{
		return splice(pipe_out, NULL, out_fd, NULL, n, 0);
	}

	ssize_t conventional_read(void)
	{
		return read(dev_fd, buf, buflen);
	}

	ssize_t conventional_write(void)
	{
		return write(out_fd, buf, n);
	}

	if (use_splice) {
		if (pipe(pipe_fd))
			err(EX_OSERR, "pipe() failed");
		pipe_out = pipe_fd[0];
		pipe_in = pipe_fd[1];
		read_dev = splice_read;
		write_out = splice_write;
	} else {
		if (!(buf = (typeof(buf)) malloc(buflen)))
			err(EX_OSERR, "malloc() failed");
		read_dev = conventional_read;
		write_out = conventional_write;
	}

	if ((dev_fd = open(dev_path, O_RDONLY, 0)) == -1)
		err(EX_NOINPUT, "open() failed on %s", dev_path);
	if (snaplen && ioctl(dev_fd, HEIO_SET_SNAPLEN, snaplen) == -1)
		err(EX_IOERR, "set snaplen ioctl() failed");

	void close_out(void)
	{
		if (close(out_fd))
			err(EX_OSERR, "close() failed on %s", out_path);
		out_fd = -1;
	}

restart:
	restart = 0;
	restart_requested = 0;

	if (out_fd != -1)
		close_out();
	if (!out_path || !strcmp(out_path, "-")) {
		if ((out_fd = dup(STDOUT_FILENO)) == -1)
			err(EX_CANTCREAT, "dup() failed on stdout");
	} else {
		if ((out_fd = open(out_path,
					O_WRONLY | O_CREAT | O_LARGEFILE | truncate, 00664)) == -1)
			err(EX_CANTCREAT, "open() failed on %s", out_path);
		if (!truncate && lseek(out_fd, 0, SEEK_END) == (off_t) -1)
			err(EX_OSERR, "error seeking to end of output file");
	}

	if (use_splice) {
		int is_fifo = 0;
		struct stat st;

		if (fstat(out_fd, &st))
			warn("fstat() failed");
		else
			is_fifo = S_ISFIFO(st.st_mode);
		pipe_in = is_fifo ? out_fd : pipe_fd[1];

		verbose2("output file is%s a FIFO\n", is_fifo ? "" : " not");
	}

	for (;;) {
		if ((restart || done) && !restart_requested) {
			if (ioctl(dev_fd, HEIO_RESTART) == -1)
				err(EX_OSERR, "reset ioctl() failed");
			verbose1("Requesting device restart.\n");
			restart_requested = 1;
		}

		if ((n = read_dev()) == -1) {
			if (errno != EINTR && errno != EAGAIN)
				err(EX_OSERR, "reading from device failed");
			continue;
		}

		if (!n) {
			verbose1("Device restarted.\n");
			if (done || ioctl(dev_fd, HEIO_GET_AT_HEAD) <= 0)
				break;
			verbose1("Reopening output file.\n");
			goto restart;
		}

		verbose3("Read %ld bytes\n", n);
		if (out_fd == pipe_in)  /* spliced directly to FIFO */
			continue;

		while (n > 0) {
			if ((m = write_out()) == -1) {
				if (errno != EINTR && errno != EAGAIN)
					err(EX_OSERR, "writing to output failed");
				continue;
			}
			verbose3("Wrote %ld bytes\n", m);
			n -= m;
		}
	}

	close_out();
	close(dev_fd);
	close(pipe_fd[0]);
	close(pipe_fd[1]);
	free(buf);

	exit(EX_OK);
}