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; }
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); }