static void do_usage(int exitcode) { printf("Usage: relay [-vdst] -f <config> [-p <port>] [-w <workers>] [-b <size>] [-q <size>]\n"); printf("\n"); printf("Options:\n"); printf(" -v print version and exit\n"); printf(" -f read <config> for clusters and routes\n"); printf(" -p listen on <port> for connections, defaults to 2003\n"); printf(" -i listen on <interface> for connections, defaults to all\n"); printf(" -l write output to <file>, defaults to stdout/stderr\n"); printf(" -w use <workers> worker threads, defaults to %d\n", get_cores()); printf(" -b server send batch size, defaults to 2500\n"); printf(" -q server queue size, defaults to 25000\n"); printf(" -S statistics sending interval in seconds, defaults to 60\n"); printf(" -m send statistics like carbon-cache.py, e.g. not cumulative\n"); printf(" -c characters to allow next to [A-Za-z0-9], defaults to -_:#\n"); printf(" -d debug mode: currently writes statistics to log, prints hash\n" " ring contents and matching position in test mode (-t)\n"); printf(" -s submission mode: don't add any metrics to the stream like\n" " statistics, report drop counts and queue pressure to log\n"); printf(" -t config test mode: prints rule matches from input on stdin\n"); printf(" -H hostname: override hostname (used in statistics)\n"); exit(exitcode); }
int main(int argc, char * const argv[]) { int stream_sock[] = {0, 0, 0}; /* tcp4, tcp6, UNIX */ int stream_socklen = sizeof(stream_sock) / sizeof(stream_sock[0]); int dgram_sock[] = {0, 0}; /* udp4, udp6 */ int dgram_socklen = sizeof(dgram_sock) / sizeof(dgram_sock[0]); char id; unsigned short listenport = 2003; int ch; size_t numaggregators; size_t numcomputes; server *internal_submission; char *listeninterface = NULL; server **servers; char *allowed_chars = NULL; int i; enum { SUB, CUM } smode = CUM; if (gethostname(relay_hostname, sizeof(relay_hostname)) < 0) snprintf(relay_hostname, sizeof(relay_hostname), "127.0.0.1"); while ((ch = getopt(argc, argv, ":hvdmstf:i:l:p:w:b:q:S:c:H:")) != -1) { switch (ch) { case 'v': do_version(); break; case 'd': if (mode == TEST) { mode = DEBUGTEST; } else { mode = DEBUG; } break; case 'm': smode = SUB; break; case 's': mode = SUBMISSION; break; case 't': if (mode == DEBUG) { mode = DEBUGTEST; } else { mode = TEST; } break; case 'f': config = optarg; break; case 'i': listeninterface = optarg; break; case 'l': relay_logfile = optarg; break; case 'p': listenport = (unsigned short)atoi(optarg); if (listenport == 0) { fprintf(stderr, "error: port needs to be a number >0\n"); do_usage(1); } break; case 'w': workercnt = (char)atoi(optarg); if (workercnt <= 0) { fprintf(stderr, "error: workers needs to be a number >0\n"); do_usage(1); } break; case 'b': batchsize = atoi(optarg); if (batchsize <= 0) { fprintf(stderr, "error: batch size needs to be a number >0\n"); do_usage(1); } break; case 'q': queuesize = atoi(optarg); if (queuesize <= 0) { fprintf(stderr, "error: queue size needs to be a number >0\n"); do_usage(1); } break; case 'S': collector_interval = atoi(optarg); if (collector_interval <= 0) { fprintf(stderr, "error: sending interval needs to be " "a number >0\n"); do_usage(1); } break; case 'c': allowed_chars = optarg; break; case 'H': snprintf(relay_hostname, sizeof(relay_hostname), "%s", optarg); break; case '?': case ':': do_usage(1); break; case 'h': default: do_usage(0); break; } } if (optind == 1 || config == NULL) do_usage(1); /* seed randomiser for dispatcher and aggregator "splay" */ srand(time(NULL)); if (workercnt == 0) workercnt = mode == SUBMISSION ? 2 : get_cores(); /* any_of failover maths need batchsize to be smaller than queuesize */ if (batchsize > queuesize) { fprintf(stderr, "error: batchsize must be smaller than queuesize\n"); exit(-1); } if (relay_logfile != NULL && mode != TEST && mode != DEBUGTEST) { FILE *f = fopen(relay_logfile, "a"); if (f == NULL) { fprintf(stderr, "error: failed to open logfile '%s': %s\n", relay_logfile, strerror(errno)); exit(-1); } relay_stdout = f; relay_stderr = f; } else { relay_stdout = stdout; relay_stderr = stderr; } relay_can_log = 1; logout("starting carbon-c-relay v%s (%s), pid=%d\n", VERSION, GIT_VERSION, getpid()); fprintf(relay_stdout, "configuration:\n"); fprintf(relay_stdout, " relay hostname = %s\n", relay_hostname); fprintf(relay_stdout, " listen port = %u\n", listenport); if (listeninterface != NULL) fprintf(relay_stdout, " listen interface = %s\n", listeninterface); fprintf(relay_stdout, " workers = %d\n", workercnt); fprintf(relay_stdout, " send batch size = %d\n", batchsize); fprintf(relay_stdout, " server queue size = %d\n", queuesize); fprintf(relay_stdout, " statistics submission interval = %ds\n", collector_interval); if (allowed_chars != NULL) fprintf(relay_stdout, " extra allowed characters = %s\n", allowed_chars); if (mode == DEBUG || mode == DEBUGTEST) fprintf(relay_stdout, " debug = true\n"); else if (mode == SUBMISSION) fprintf(relay_stdout, " submission = true\n"); fprintf(relay_stdout, " routes configuration = %s\n", config); fprintf(relay_stdout, "\n"); if (router_readconfig(&clusters, &routes, config, queuesize, batchsize) == 0) { logerr("failed to read configuration '%s'\n", config); return 1; } router_optimise(&routes); numaggregators = aggregator_numaggregators(); numcomputes = aggregator_numcomputes(); #define dbg (mode == DEBUG || mode == DEBUGTEST ? 2 : 0) if (numaggregators > 10 && !dbg) { fprintf(relay_stdout, "parsed configuration follows:\n" "(%zd aggregations with %zd computations omitted " "for brevity)\n", numaggregators, numcomputes); router_printconfig(relay_stdout, 0, clusters, routes); } else { fprintf(relay_stdout, "parsed configuration follows:\n"); router_printconfig(relay_stdout, 1 + dbg, clusters, routes); } fprintf(relay_stdout, "\n"); /* shortcut for rule testing mode */ if (mode == TEST || mode == DEBUGTEST) { char metricbuf[METRIC_BUFSIZ]; char *p; fflush(relay_stdout); while (fgets(metricbuf, sizeof(metricbuf), stdin) != NULL) { if ((p = strchr(metricbuf, '\n')) != NULL) *p = '\0'; router_test(metricbuf, routes); } exit(0); } if (signal(SIGINT, exit_handler) == SIG_ERR) { logerr("failed to create SIGINT handler: %s\n", strerror(errno)); return 1; } if (signal(SIGTERM, exit_handler) == SIG_ERR) { logerr("failed to create SIGTERM handler: %s\n", strerror(errno)); return 1; } if (signal(SIGQUIT, exit_handler) == SIG_ERR) { logerr("failed to create SIGQUIT handler: %s\n", strerror(errno)); return 1; } if (signal(SIGHUP, hup_handler) == SIG_ERR) { logerr("failed to create SIGHUP handler: %s\n", strerror(errno)); return 1; } if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { logerr("failed to ignore SIGPIPE: %s\n", strerror(errno)); return 1; } workers = malloc(sizeof(dispatcher *) * (1 + workercnt + 1)); if (workers == NULL) { logerr("failed to allocate memory for workers\n"); return 1; } if (bindlisten(stream_sock, &stream_socklen, dgram_sock, &dgram_socklen, listeninterface, listenport) < 0) { logerr("failed to bind on port %s:%d: %s\n", listeninterface == NULL ? "" : listeninterface, listenport, strerror(errno)); return -1; } for (ch = 0; ch < stream_socklen; ch++) { if (dispatch_addlistener(stream_sock[ch]) != 0) { logerr("failed to add listener\n"); return -1; } } for (ch = 0; ch < dgram_socklen; ch++) { if (dispatch_addlistener_udp(dgram_sock[ch]) != 0) { logerr("failed to listen to datagram socket\n"); return -1; } } if ((workers[0] = dispatch_new_listener()) == NULL) logerr("failed to add listener\n"); if (allowed_chars == NULL) allowed_chars = "-_:#"; logout("starting %d workers\n", workercnt); for (id = 1; id < 1 + workercnt; id++) { workers[id + 0] = dispatch_new_connection(routes, allowed_chars); if (workers[id + 0] == NULL) { logerr("failed to add worker %d\n", id); break; } } workers[id + 0] = NULL; if (id < 1 + workercnt) { logerr("shutting down due to errors\n"); keep_running = 0; } /* server used for delivering metrics produced inside the relay, * that is collector (statistics) and aggregator (aggregations) */ if ((internal_submission = server_new("internal", listenport, CON_PIPE, NULL, 3000 + (numcomputes * 3), batchsize)) == NULL) { logerr("failed to create internal submission queue, shutting down\n"); keep_running = 0; } if (numaggregators > 0) { logout("starting aggregator\n"); if (!aggregator_start(internal_submission)) { logerr("shutting down due to failure to start aggregator\n"); keep_running = 0; } } logout("starting statistics collector\n"); collector_start(&workers[1], clusters, internal_submission, smode == CUM); logout("startup sequence complete\n"); /* workers do the work, just wait */ while (keep_running) sleep(1); logout("shutting down...\n"); /* make sure we don't accept anything new anymore */ for (ch = 0; ch < stream_socklen; ch++) dispatch_removelistener(stream_sock[ch]); destroy_usock(listenport); logout("listeners for port %u closed\n", listenport); /* since workers will be freed, stop querying the structures */ collector_stop(); logout("collector stopped\n"); if (numaggregators > 0) { aggregator_stop(); logout("aggregator stopped\n"); } server_shutdown(internal_submission); /* give a little time for whatever the collector/aggregator wrote, * to be delivered by the dispatchers */ usleep(500 * 1000); /* 500ms */ /* make sure we don't write to our servers any more */ logout("stopped worker"); for (id = 0; id < 1 + workercnt; id++) dispatch_stop(workers[id + 0]); for (id = 0; id < 1 + workercnt; id++) { dispatch_shutdown(workers[id + 0]); fprintf(relay_stdout, " %d", id + 1); fflush(relay_stdout); } fprintf(relay_stdout, "\n"); router_shutdown(); servers = router_getservers(clusters); logout("stopped server"); for (i = 0; servers[i] != NULL; i++) server_stop(servers[i]); for (i = 0; servers[i] != NULL; i++) { server_shutdown(servers[i]); fprintf(relay_stdout, " %d", i + 1); fflush(relay_stdout); } fprintf(relay_stdout, "\n"); logout("routing stopped\n"); router_free(clusters, routes); free(workers); return 0; }
static int create_type9(RECORD **anrecord, struct finger_view_minutiae_record *fvmr, unsigned int idc) { FIELD *field = NULL; SUBFIELD *subfield = NULL; ITEM *item = NULL; RECORD *lrecord; // For local convenience struct finger_minutiae_data **fmds = NULL; struct ridge_count_data **rcds = NULL; struct core_data **cds; struct delta_data **dds; char buf[16]; int mincnt, minidx, rdgcnt; int cnt, i; unsigned int x, y; if (new_ANSI_NIST_record(anrecord, TYPE_9_ID) != 0) ALLOC_ERR_EXIT("Type-9 Record"); lrecord = *anrecord; /*** 9.001 - Length ***/ // Set to 0 now, will recalculate later APPEND_TYPE9_FIELD(lrecord, LEN_ID, "0"); /*** 9.002 - IDC value ***/ snprintf(buf, sizeof(buf), IDC_FMT, idc); APPEND_TYPE9_FIELD(lrecord, IDC_ID, buf); /*** 9.003 - Impression type ***/ CRW(fvmr->impression_type, MIN_TABLE_5_CODE, MAX_TABLE_5_CODE, "Impression type"); snprintf(buf, sizeof(buf), "%d", fvmr->impression_type); APPEND_TYPE9_FIELD(lrecord, IMP_ID, buf); /*** 9.004 - Minutiae format ***/ APPEND_TYPE9_FIELD(lrecord, FMT_ID, STD_STR); /*** 9.005 - Originating fingerprint reading system ***/ if (value2subfield(&subfield, "EXISTING IMAGE") != 0) ERR_OUT("creating Type-9 subfield"); if (value2item(&item, AUTO_STR) != 0) ERR_OUT("creating Type-9 item"); if (append_ANSI_NIST_subfield(subfield, item) != 0) ERR_OUT("appending Type-9 item"); if (new_ANSI_NIST_field(&field, TYPE_9_ID, OFR_ID) != 0) ERR_OUT("creating Type-9 field"); if (append_ANSI_NIST_field(field, subfield) != 0) ERR_OUT("appending Type-9 subfield"); if (append_ANSI_NIST_record(lrecord, field) != 0) ERR_OUT("appending Type-9 field"); /*** 9.006 - Finger position ***/ snprintf(buf, sizeof(buf), "%02d", fvmr->finger_number); APPEND_TYPE9_FIELD(lrecord, FGP2_ID, buf); /*** 9.007 - Fingerprint pattern classification ***/ if (value2subfield(&subfield, TBL_STR) != 0) ERR_OUT("creating Type-9 subfield"); if (value2item(&item, "UN") != 0) ERR_OUT("creating Type-9 item"); if (append_ANSI_NIST_subfield(subfield, item) != 0) ERR_OUT("appending Type-9 item"); if (new_ANSI_NIST_field(&field, TYPE_9_ID, FPC_ID) != 0) ERR_OUT("creating Type-9 field"); if (append_ANSI_NIST_field(field, subfield) != 0) ERR_OUT("appending Type-9 subfield"); if (append_ANSI_NIST_record(lrecord, field) != 0) ERR_OUT("appending Type-9 field"); /*** 9.008 - Core position ***/ cnt = get_core_count(fvmr); if (cnt > 0) { if (new_ANSI_NIST_field(&field, TYPE_9_ID, CRP_ID) != 0) ERR_OUT("allocating field"); cds = (struct core_data **) malloc( cnt * sizeof(struct core_data **)); if (cds == NULL) ALLOC_ERR_EXIT("Core data"); if (get_cores(fvmr, cds) != cnt) ERR_OUT("retrieving core data"); for (i = 0; i < cnt; i++) { convert_xy(fvmr->fmr->x_image_size, fvmr->fmr->y_image_size, fvmr->fmr->x_resolution, fvmr->fmr->y_resolution, cds[i]->x_coord, cds[i]->y_coord, &x, &y); snprintf(buf, sizeof(buf), "%04u%04u", x, y); if (value2subfield(&subfield, buf) != 0) ERR_OUT("creating subfield"); if (append_ANSI_NIST_field(field, subfield) != 0) ERR_OUT("appending subfield"); } if (append_ANSI_NIST_record(lrecord, field) != 0) ERR_OUT("adding field to record"); } else if (cnt < 0) ERR_OUT("getting core record count"); /*** 9.009 - Delta(s) position ***/ cnt = get_delta_count(fvmr); if (cnt > 0) { if (new_ANSI_NIST_field(&field, TYPE_9_ID, DLT_ID) != 0) ERR_OUT("creating Type-9 field"); dds = (struct delta_data **) malloc( cnt * sizeof(struct delta_data **)); if (dds == NULL) ALLOC_ERR_EXIT("Delta data"); if (get_deltas(fvmr, dds) != cnt) ERR_OUT("retrieving delta data"); for (i = 0; i < cnt; i++) { convert_xy(fvmr->fmr->x_image_size, fvmr->fmr->y_image_size, fvmr->fmr->x_resolution, fvmr->fmr->y_resolution, dds[i]->x_coord, dds[i]->y_coord, &x, &y); snprintf(buf, sizeof(buf), "%04u%04u", x, y); if (value2subfield(&subfield, buf) != 0) ERR_OUT("creating subfield"); if (append_ANSI_NIST_field(field, subfield) != 0) ERR_OUT("appending subfield"); } if (append_ANSI_NIST_record(lrecord, field) != 0) ERR_OUT("adding field to record"); } else if (cnt < 0) ERR_OUT("getting delta record count"); /*** 9.010 - Number of minutiae ***/ mincnt = get_fmd_count(fvmr); if (mincnt < 0) ERR_OUT("getting minutiae count"); snprintf(buf, sizeof(buf), "%d", mincnt); APPEND_TYPE9_FIELD(lrecord, MIN_ID, buf); /*** 9.011 - Minutiae ridge count indicator ***/ rdgcnt = get_rcd_count(fvmr); if (rdgcnt > 0) { rcds = (struct ridge_count_data **) malloc( rdgcnt * sizeof(struct ridge_count_data **)); if (rcds == NULL) ALLOC_ERR_EXIT("Ridge Count data"); if (get_rcds(fvmr, rcds) != rdgcnt) ERR_OUT("retrieving ridge count data"); APPEND_TYPE9_FIELD(lrecord, RDG_ID, "1"); } else if (rdgcnt < 0) ERR_OUT("getting ridge record count"); else APPEND_TYPE9_FIELD(lrecord, RDG_ID, "0"); /*** 9.012 - Minutiae and ridge count data ***/ fmds = (struct finger_minutiae_data **) malloc( mincnt * sizeof(struct finger_minutiae_data **)); if (fmds == NULL) ALLOC_ERR_EXIT("Finger Minutiae data"); if (get_fmds(fvmr, fmds) != mincnt) ERR_OUT("retrieving minutiae data"); if (new_ANSI_NIST_field(&field, TYPE_9_ID, MRC_ID) != 0) ERR_OUT("creating Type-9 field"); for (minidx = 0; minidx < mincnt; minidx++) { unsigned int theta, rdgidx, minqual; char mintype; int idxnum = minidx + 1; // Index number snprintf(buf, sizeof(buf), "%03d", idxnum); if (value2subfield(&subfield, buf) != 0) ERR_OUT("creating Type-9 subfield"); // X, Y, and theta values convert_xy(fvmr->fmr->x_image_size, fvmr->fmr->y_image_size, fvmr->fmr->x_resolution, fvmr->fmr->y_resolution, fmds[minidx]->x_coord, fmds[minidx]->y_coord, &x, &y); convert_theta(fmds[minidx]->angle, &theta); snprintf(buf, sizeof(buf), "%04u%04u%03u", x, y, theta); if (value2item(&item, buf) != 0) ERR_OUT("creating Type-9 item"); if (append_ANSI_NIST_subfield(subfield, item) != 0) ERR_OUT("appending Type-9 item"); // Quality measure convert_quality(fmds[minidx]->quality, &minqual); snprintf(buf, sizeof(buf), "%u", minqual); if (value2item(&item, buf) != 0) ERR_OUT("creating Type-9 item"); if (append_ANSI_NIST_subfield(subfield, item) != 0) ERR_OUT("appending Type-9 item"); // Minutia type designation convert_type(fmds[minidx]->type, &mintype); snprintf(buf, sizeof(buf), "%c", mintype); if (value2item(&item, buf) != 0) ERR_OUT("creating Type-9 item"); if (append_ANSI_NIST_subfield(subfield, item) != 0) ERR_OUT("appending Type-9 item"); // Ridge count data: If the one of the index numbers // in the record matches the minutia index, then add that // ridge count data to the Type-9 record, using the index // number that is the 'other'. for (rdgidx = 0; rdgidx < rdgcnt; rdgidx++) { if ((rcds[rdgidx]->index_one == idxnum) || (rcds[rdgidx]->index_two == idxnum)) { snprintf(buf, sizeof(buf), "%u,%u", (rcds[rdgidx]->index_one == idxnum) ? rcds[rdgidx]->index_two : rcds[rdgidx]->index_one, rcds[rdgidx]->count); if (value2item(&item, buf) != 0) ERR_OUT("creating Type-9 item"); if (append_ANSI_NIST_subfield(subfield, item) != 0) ERR_OUT("appending Type-9 item"); } } if (append_ANSI_NIST_field(field, subfield) != 0) ERR_OUT("appending Type-9 subfield"); } free(fmds); if (append_ANSI_NIST_record(lrecord, field) != 0) ERR_OUT("appending Type-9 field"); /*** End of minutiae and ridge count */ // Calculate and update the record length field if (update_ANSI_NIST_tagged_record_LEN(lrecord) != 0) ERR_OUT("updating Type-9 record length"); return 0; err_out: fprintf(stderr, "Error creating Type-9 record\n"); if (item != NULL) free_ANSI_NIST_item(item); if (subfield != NULL) free_ANSI_NIST_subfield(subfield); if (field != NULL) free_ANSI_NIST_field(field); if (lrecord != NULL) free_ANSI_NIST_record(lrecord); if (fmds != NULL) free(fmds); return -1; }
int parse_options(int ch, char *a[]) { // clear the options structure bzero(&options, sizeof(options)); /* options.packets_to_collect = -1; options.bpf_filter[0] = '\0'; options.interface[0] = '\0'; options.verbose = 0; options.output_filename[0] = '\0'; options.fp = stdout; */ int c; while (1) { static struct option long_options[] = { /* These options set a flag. */ {"verbose", no_argument, &(options.verbose), 1}, {"brief", no_argument, &(options.verbose), 0}, /* These options don’t set a flag. We distinguish them by their indices. */ {"interface", required_argument, 0, 'i'}, {"bpf", required_argument, 0, 'b'}, {"packets", required_argument, 0, 'p'}, {"help", no_argument, 0, 'h'}, {"filename", required_argument, 0, 'f'}, {"mqtthost", required_argument, 0, 'm'}, {"mqttport", required_argument, 0, 'q'}, {0, 0, 0, 0}}; int option_index = 0; c = getopt_long(ch, a, "vbi:b:p:hf:m:q:", long_options, &option_index); if (c == -1) break; switch (c) { case 0: if (long_options[option_index].flag != 0) break; printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); break; case 'i': // printf ("option -i with value `%s'\n", optarg); strncpy(options.interface, optarg, DEFAULT_OPT_STRING_LEN-1); break; case 'p': options.packets_to_collect = atoi(optarg); break; case 'b': strncpy(options.bpf_filter, optarg, DEFAULT_OPT_STRING_LEN-1); break; case 'f': strncpy(options.output_filename, optarg, DEFAULT_OPT_STRING_LEN-1); struct stat st; stat(options.output_filename, &st); if (st.st_mode & S_IWUSR) { options.fp = fopen(options.output_filename, "a"); } break; case 'h': usage(); return -1; break; case 'm': strncpy(options.mqtt_host, optarg, DEFAULT_OPT_STRING_LEN-1); break; case 'q': options.mqtt_port = atoi(optarg); break; default: break; } } // Deal with the default options if (options.interface[0] == '\0') { syslog(LOG_ERR, "[Options] No interface specified"); usage(); return -1; } if (options.bpf_filter[0] == '\0') { strncpy(options.bpf_filter, DEFAULT_FILTER, strlen(DEFAULT_FILTER)); } if (options.mqtt_host[0] == '\0') { strncpy(options.mqtt_host, DEFAULT_MQTT_HOST, strlen(DEFAULT_MQTT_HOST)); } if (options.mqtt_port == 0) { options.mqtt_port = DEFAULT_MQTT_PORT; } if (options.fp == 0) { options.fp = stdout; } options.cores = get_cores(); show_options(); return 1; }