Пример #1
0
static int itf_sd_init()
{
	unsigned long hd = 0;

	if ((hd = CfgInitialize(cfgfile)) == 0ul) {
		LOGERROR("Parsing configuration file [%s] failed.", cfgfile);
		return -1;
	}

	call_adap_to = adapter_register_archive(hd,
			(char *)"Call.Archive", CallOutputCallback);
	sms_adap_to = adapter_register_archive(hd,
			(char *)"SMS.Archive", SMSOutputCallback);
	power_adap_to = adapter_register_archive(hd,
			(char *)"Power.Archive", PowerOutputCallback);
	switch_adap_to = adapter_register_archive(hd,
			(char *)"Switch.Archive", SwitchOutputCallback);
	location_adap_to = adapter_register_archive(hd,
			(char *)"Location.Archive", LocationOutputCallback);

	if ((call_adap_to == NULL) || (power_adap_to == NULL) ||
			(sms_adap_to == NULL) || (switch_adap_to == NULL) ||
			(location_adap_to == NULL)) {
		CfgInvalidate(hd);
		return -1;
	}

	itf_sd_init_lacci_mapping(hd);

	CfgInvalidate(hd);

	if (!InitDbus(PKTTYPE_CDR, PKTTYPE_CDR_BSSAP, g_dbus_cdr))
		return -1;
	if (!InitDbus(PKTTYPE_EVENT, PKTTYPE_EVENT_BSSAP, g_dbus_event))
		return -1;

	swdbus_update_filter(
			g_dbus_event, filter_parse((char *)"(PROTOCOL IN [1, 2])"));

	g_timer = timer_mgr_create_timerlist(NULL, TIMERMGR_SOURCE_LOCAL,
			TimerCallback, NULL, "SendCDRConvertStatistics");
	timer_mgr_add_timer_periodic(g_timer, 300, NULL);

	return 0;
}
Пример #2
0
cache_entry *
load_cache_table (char *file_name)
{
  cache_entry *cache = NULL;
  cache_entry **last = &cache;
  table *file = table_open (file_name);
  table_entry *entry;
  while ((entry = table_read (file)) != NULL)
    {
      cache_entry *new_rule = ZALLOC (cache_entry);
      new_rule->line = entry->line;
      new_rule->entry_type = name2i (entry->field[ca_type], cache_type_map);
      new_rule->name = entry->field[ca_derived_name];
      filter_parse (&new_rule->original_fields, entry->field[ca_field_name]);
      new_rule->type = entry->field[ca_type_def];
      /* expression is the concatenation of the remaining fields */
      if (entry->nr_fields > ca_expression)
	{
	  int len = 0;
	  int chi;
	  for (chi = ca_expression; chi < entry->nr_fields; chi++)
	    {
	      len += strlen (" : ") + strlen (entry->field[chi]);
	    }
	  new_rule->expression = NZALLOC (char, len);
	  strcpy (new_rule->expression, entry->field[ca_expression]);
	  for (chi = ca_expression + 1; chi < entry->nr_fields; chi++)
	    {
	      strcat (new_rule->expression, " : ");
	      strcat (new_rule->expression, entry->field[chi]);
	    }
	}
      /* insert it */
      *last = new_rule;
      last = &new_rule->next;
    }
Пример #3
0
int login_handler(struct worker_t *self, struct client_t *c, int l4proto, char *s, int len)
{
	int argc;
	char *argv[256];
	int i, rc;
	
	/* make it null-terminated for our string processing */
	char *e = s + len;
	*e = 0;
	hlog(LOG_DEBUG, "%s: login string: '%s' (%d)", c->addr_rem, s, len);
	
	/* parse to arguments */
	if ((argc = parse_args_noshell(argv, s)) == 0 || *argv[0] == '#')
		return 0;
	
	if (argc < 2) {
		hlog(LOG_WARNING, "%s: Invalid login string, too few arguments: '%s'", c->addr_rem, s);
		rc = client_printf(self, c, "# Invalid login string, too few arguments\r\n");
		goto failed_login;
	}
	
	if (strcasecmp(argv[0], "user") != 0) {
		if (strcasecmp(argv[0], "GET") == 0)
			c->failed_cmds = 10; /* bail out right away for a HTTP client */
		
		c->failed_cmds++;
		hlog(LOG_WARNING, "%s: Invalid login string, no 'user': '******'", c->addr_rem, s);
		rc = client_printf(self, c, "# Invalid login command\r\n");
		goto failed_login;
	}
	
	char *username = argv[1];
	
	/* limit username length */
	if (strlen(username) > CALLSIGNLEN_MAX) {
		hlog(LOG_WARNING, "%s: Invalid login string, too long 'user' username: '******'", c->addr_rem, c->username);
		username[CALLSIGNLEN_MAX] = 0;
		rc = client_printf(self, c, "# Invalid username format\r\n");
		goto failed_login;
	}
	
#ifndef FIXED_IOBUFS
	c->username = hstrdup(username);
#else
	strncpy(c->username, username, sizeof(c->username));
	c->username[sizeof(c->username)-1] = 0;
#endif
	c->username_len = strlen(c->username);
	
	/* check the username against a static list of disallowed usernames */
	for (i = 0; (disallow_login_usernames[i]); i++) {
		if (strcasecmp(c->username, disallow_login_usernames[i]) == 0) {
			hlog(LOG_WARNING, "%s: Login by user '%s' not allowed", c->addr_rem, c->username);
			rc = client_printf(self, c, "# Login by user not allowed\r\n");
			goto failed_login;
		}
	}
	
	/* make sure the callsign is OK on the APRS-IS */
	if (check_invalid_q_callsign(c->username, c->username_len)) {
		hlog(LOG_WARNING, "%s: Invalid login string, invalid 'user': '******'", c->addr_rem, c->username);
		rc = client_printf(self, c, "# Invalid username format\r\n");
		goto failed_login;
	}
	
	int given_passcode = -1;
	
	for (i = 2; i < argc; i++) {
		if (strcasecmp(argv[i], "pass") == 0) {
			if (++i >= argc) {
				hlog(LOG_WARNING, "%s/%s: No passcode after pass command", c->addr_rem, username);
				break;
			}
			
			given_passcode = atoi(argv[i]);
			if (given_passcode >= 0)
				if (given_passcode == aprs_passcode(c->username))
					c->validated = 1;
		} else if (strcasecmp(argv[i], "vers") == 0) {
			/* Collect application name and version separately.
			 * Some clients only give out application name but
			 * no version. If those same applications do try to
			 * use filter or udp, the filter/udp keyword will end
			 * up as the version number. So good luck with that.
			 */
			 
			if (i+1 >= argc) {
				hlog(LOG_INFO, "%s/%s: No application name after 'vers' in login", c->addr_rem, username);
				break;
			}
			
			login_set_app_name(c, argv[i+1], (i+2 < argc) ? argv[i+2] : "");
			i += 2;

		} else if (strcasecmp(argv[i], "udp") == 0) {
			if (++i >= argc) {
				hlog(LOG_WARNING, "%s/%s: Missing UDP port number after UDP command", c->addr_rem, username);
				break;
			}
			
			int udp_port = atoi(argv[i]);
			if (udp_port < 1024 || udp_port > 65535) {
				hlog(LOG_WARNING, "%s/%s: UDP port number %s is out of range", c->addr_rem, username, argv[i]);
				break;
			}

			if (login_setup_udp_feed(c, udp_port) != 0) {
				/* Sorry, no UDP service for this port.. */
				hlog(LOG_DEBUG, "%s/%s: Requested UDP on client port with no UDP configured", c->addr_rem, username);
				rc = client_printf(self, c, "# No UDP service available on this port\r\n");
				if (rc < -2)
					return rc; // client got destroyed
					
			}

		} else if (strstr(argv[i], "filter")) {
                        /* Follows javaaprssrvr's example - any command having 'filter' in the
                         * end is OK.
                         */
			if (!(c->flags & CLFLAGS_USERFILTEROK)) {
				rc = client_printf(self, c, "# No user-specified filters on this port\r\n");
				if (rc < -2)
                        		return rc; // client got destroyed
				break;
			}
			
			/* copy the null-separated filter arguments back to a space-separated
			 * string, for the status page to show
			 */
			char *fp = c->filter_s;
			char *fe = c->filter_s + FILTER_S_SIZE;
			int f_non_first = 0;
			
			while (++i < argc) {
				int l = strlen(argv[i]);
				if (fp + l + 2 < fe) {
					if (f_non_first) {
						*fp++ = ' ';
					}
					memcpy(fp, argv[i], l);
					fp += l;
					*fp = 0;
					
					f_non_first = 1;	
				}
				
				/* parse filters in argv[i] */
				rc = filter_parse(c, argv[i], 1);
				if (rc) {
					rc = client_printf( self, c, "# Parse errors on filter spec: '%s'\r\n", argv[i]);
					if (rc < -2)
						return rc; // The client probably got destroyed!
				}
			}
		}
	}
	
	/* ok, login succeeded, switch handler */
	c->handler = &incoming_handler; /* handler of all incoming APRS-IS data during a connection */
	
	rc = client_printf( self, c, "# logresp %s %s, server %s\r\n",
			    username,
			    (c->validated) ? "verified" : "unverified",
			    serverid );
	if (rc < -2)
		return rc; // The client probably got destroyed!

	c->keepalive = now + keepalive_interval/2 + random() % keepalive_interval;
	c->state = CSTATE_CONNECTED;
	
	hlog(LOG_DEBUG, "%s: login '%s'%s%s%s%s%s%s%s%s",
	     c->addr_rem, username,
	     (c->validated) ? " pass_ok" : "",
	     (!c->validated && given_passcode >= 0) ? " pass_invalid" : "",
	     (given_passcode < 0) ? " pass_none" : "",
	     (c->udp_port) ? " UDP" : "",
	     (c->app_name) ? " app " : "",
	     (c->app_name) ? c->app_name : "",
	     (c->app_version) ? " ver " : "",
	     (c->app_version) ? c->app_version : ""
	);
	
	/* Add the client to the client list.
	 *
	 * If the client logged in with a valid passcode, check if there are
	 * other validated clients logged in with the same username.
	 * If one is found, it needs to be disconnected.
	 *
	 * The lookup is done while holding the write lock to the clientlist,
	 * instead of a separate lookup call, so that two clients logging in
	 * at exactly the same time won't make it.
	 */
	 
	int old_fd = clientlist_add(c);
	if (c->validated && old_fd != -1) {
		hlog(LOG_INFO, "fd %d: Disconnecting duplicate validated client with username '%s'", old_fd, username);
		/* The other client may be on another thread, so cannot client_close() it.
		 * There is a small potential race here, if the old client disconnected and
		 * the fd was recycled for another client right after the clientlist check.
		 */
		shutdown(old_fd, SHUT_RDWR);
	}
	
	return 0;

failed_login:
	
	/* if we already lost the client, just return */
	if (rc < -2)
		return rc;
	
	c->failed_cmds++;
	if (c->failed_cmds >= 3) {
		client_close(self, c, CLIERR_LOGIN_RETRIES);
		return -3;
	}
	
	return rc;
}
Пример #4
0
static void parse_options(struct ts *ts, int argc, char **argv) {
	int j, i, ca_err = 0, server_err = 1, input_addr_err = 0, output_addr_err = 0, ident_err = 0, port_set = 0;
	while ((j = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
		if (j == '?')
			exit(EXIT_FAILURE);
		switch (j) {
			case 'i': // -- ident
				ts->ident = optarg;
				break;
			case 'd': // --daemon
				ts->pidfile = optarg;
				break;
			case 'N': // --notify-program
				ts->notify_program = optarg;
				break;

			case 'S': // --syslog
				ts->syslog_active = 1;
				ts->syslog_remote = 0;
				break;
			case 'l': // --syslog-host
				ts->syslog_host = optarg;
				ts->syslog_active = 1;
				ts->syslog_remote = 1;
				break;
			case 'L': // --syslog-port
				ts->syslog_port = atoi(optarg);
				break;
			case 'F': // --log-file
				log_filename = optarg;
				break;

			case 'I': // --input
				input_addr_err = !parse_io_param(&ts->input, optarg, O_RDONLY, 0);
				break;
			case '1': // --input-source
				if (!inet_aton(optarg, &ts->input.isrc)) {
					fprintf(stderr, "ERROR: Can't parse input-source IP address: %s\n", optarg);
					exit(EXIT_FAILURE);
				}
				break;
			case 'R': // --input-rtp
				ts->rtp_input = !ts->rtp_input;
				break;
			case 'z': // --input-ignore-disc
				ts->ts_discont = !ts->ts_discont;
				break;
			case 'M': // --input-service
				ts->forced_service_id = strtoul(optarg, NULL, 0) & 0xffff;
				break;
			case 'T': // --input-buffer
				ts->input_buffer_time = strtoul(optarg, NULL, 0);
				break;
			case 'W': // --input-dump
				ts->input_dump_filename = optarg;
				break;

			case 'O': // --output
				output_addr_err = !parse_io_param(&ts->output, optarg,
					O_CREAT | O_WRONLY | O_TRUNC,
					S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
				break;
			case 'o': // --output-intf
				if (strchr(optarg, '.'))
					inet_aton(optarg, &ts->output.intf);
				else
					ts->output.v6_if_index = atoi(optarg);
				break;
			case 't': // --output-ttl
				ts->output.ttl = atoi(optarg);
				break;
			case 'r': // --output-rtp
				ts->rtp_output = 1;
				break;
			case 'k': // --output-rtp-ssrc
				ts->rtp_ssrc = strtoul(optarg, NULL, 0);
				break;
			case 'g': // --output-tos
				ts->output.tos = (uint8_t)strtol(optarg, NULL, 0);
				break;
			case 'u': // --no-output-on-error
				ts->no_output_on_error = !ts->no_output_on_error;
				break;
			case 'p': // --no-output-filter
				ts->pid_filter = !ts->pid_filter;
				break;
			case 'y': // --output-nit-pass
				ts->nit_passthrough = !ts->nit_passthrough;
				break;
			case 'w': // --output-eit-pass
				ts->eit_passthrough = !ts->eit_passthrough;
				break;
			case 'x': // --output-tdt-pass
				ts->tdt_passthrough = !ts->tdt_passthrough;
				break;
			case 'c': // --ca-system
				if (strcasecmp("IRDETO", optarg) == 0)
					ts->req_CA_sys = CA_IRDETO;
				else if (strcasecmp("CONNAX", optarg) == 0 || strcasecmp("CONAX", optarg) == 0)
					ts->req_CA_sys = CA_CONAX;
				else if (strcasecmp("CRYPTOWORKS", optarg) == 0)
					ts->req_CA_sys = CA_CRYPTOWORKS;
				else if (strcasecmp("SECA", optarg) == 0 || strcasecmp("MEDIAGUARD", optarg) == 0)
					ts->req_CA_sys = CA_SECA;
				else if (strcasecmp("VIACCESS", optarg) == 0)
					ts->req_CA_sys = CA_VIACCESS;
				else if (strcasecmp("VIDEOGUARD", optarg) == 0 || strcasecmp("NDS", optarg) == 0)
					ts->req_CA_sys = CA_VIDEOGUARD;
				else if (strcasecmp("NAGRA", optarg) == 0)
					ts->req_CA_sys = CA_NAGRA;
				else if (strcasecmp("DRE-CRYPT", optarg) == 0 || strcasecmp("DRECRYPT", optarg) == 0)
					ts->req_CA_sys = CA_DRECRYPT;
				else if (strcasecmp("BULCRYPT", optarg) == 0)
					ts->req_CA_sys = CA_BULCRYPT;
				else if (strcasecmp("GRIFFIN", optarg) == 0)
					ts->req_CA_sys = CA_GRIFFIN;
				else if (strcasecmp("DGCRYPT", optarg) == 0)
					ts->req_CA_sys = CA_DGCRYPT;
				else
					ca_err = 1;
				break;
			case 'C': // --caid
				ts->forced_caid = strtoul(optarg, NULL, 0) & 0xffff;
				break;
			case 'Y': // --const-cw
				ts->camd.constant_codeword = 1;
				if (strlen(optarg) > 2 && optarg[0] == '0' && optarg[1] == 'x')
					optarg += 2;
				if (strlen(optarg) != CODEWORD_LENGTH * 2) {
					fprintf(stderr, "ERROR: Constant code word should be %u characters long.\n", CODEWORD_LENGTH * 2);
					exit(EXIT_FAILURE);
				}
				if (decode_hex_string(optarg, ts->camd.key->cw, strlen(optarg)) < 0) {
					fprintf(stderr, "ERROR: Invalid hex string for constant code word: %s\n", optarg);
					exit(EXIT_FAILURE);
				}
				camd_set_cw(ts, ts->camd.key->cw, 0);
				ts->camd.key->is_valid_cw = 1;
				break;
			case 'Q': // --biss-key
				ts->camd.constant_codeword = 1;
				if (strlen(optarg) > 2 && optarg[0] == '0' && optarg[1] == 'x')
					optarg += 2;
				uint8_t *key = ts->camd.key->cw;
				// Sometimes the BISS keys are entered with their checksums already calculated (16 symbols, 8 bytes)
				// This is the same as constant cw with the same key for even and odd
				if (strlen(optarg) == (BISSKEY_LENGTH + 2) * 2) {
					if (decode_hex_string(optarg, key, strlen(optarg)) < 0) {
						fprintf(stderr, "ERROR: Invalid hex string for BISS key: %s\n", optarg);
						exit(EXIT_FAILURE);
					}
				} else {
					// BISS key without checksum (12 symbols, 6 bytes)
					if (strlen(optarg) != BISSKEY_LENGTH * 2) {
						fprintf(stderr, "ERROR: BISS key should be %u characters long.\n", BISSKEY_LENGTH * 2);
						exit(EXIT_FAILURE);
					}
					if (decode_hex_string(optarg, key, strlen(optarg)) < 0) {
						fprintf(stderr, "ERROR: Invalid hex string for BISS key: %s\n", optarg);
						exit(EXIT_FAILURE);
					}
					// Calculate BISS KEY crc
					memmove(key + 4, key + 3, 3);
					key[3] = (uint8_t)(key[0] + key[1] + key[2]);
					key[7] = (uint8_t)(key[4] + key[5] + key[6]);
				}
				// Even and odd keys are the same
				memcpy(key + 8, key, 8);
				camd_set_cw(ts, ts->camd.key->cw, 0);
				ts->camd.key->is_valid_cw = 1;
				break;

			case 'A': // --camd-proto
				if (strcasecmp(optarg, "cs378x") == 0) {
					camd_proto_cs378x(&ts->camd.ops);
				} else if (strcasecmp(optarg, "newcamd") == 0) {
					camd_proto_newcamd(&ts->camd.ops);
				} else {
					fprintf(stderr, "Unknown CAMD protocol: %s\n", optarg);
					exit(EXIT_FAILURE);
				}
				break;
			case 's': // --camd-server
				server_err = !parse_host_and_port(optarg, &ts->camd.hostname, &ts->camd.service, &port_set);
				break;
			case 'U': // --camd-user
				if (strlen(optarg) < 64)
					ts->camd.user = optarg;
				break;
			case 'P': // --camd-pass
				ts->camd.pass = optarg;
				break;
			case 'B': // --camd-des-key
				if (strlen(optarg) > 2 && optarg[0] == '0' && optarg[1] == 'x')
					optarg += 2;
				if (strlen(optarg) != DESKEY_LENGTH) {
					fprintf(stderr, "ERROR: des key should be %u characters long.\n", DESKEY_LENGTH);
					exit(EXIT_FAILURE);
				}
				strncpy(ts->camd.newcamd.hex_des_key, optarg, sizeof(ts->camd.newcamd.hex_des_key) - 1);
				ts->camd.newcamd.hex_des_key[sizeof(ts->camd.newcamd.hex_des_key) - 1] = 0;
				break;
			case '4': // --ipv4
				ai_family = AF_INET;
				break;
			case '6': // --ipv6
				ai_family = AF_INET6;
				break;

			case 'e': // --emm
				ts->process_emm = !ts->process_emm;
				break;
			case 'Z': // --emm-pid
				ts->forced_emm_pid = strtoul(optarg, NULL, 0) & 0x1fff;
				break;
			case 'E': // --emm-only
				ts->process_emm = 1;
				ts->process_ecm = 0;
				ts->output_stream = 0;
				break;
			case 'f': // --emm-report-time
				ts->emm_report_interval = strtoul(optarg, NULL, 10);
				if (ts->emm_report_interval > 86400)
					ts->emm_report_interval = 86400;
				break;

			case 'a': // --emm-filter
				if (ts->emm_filters_num + 1 > MAX_FILTERS) {
					fprintf(stderr, "ERROR: Maximum allowed filters are %d.\n", MAX_FILTERS);
					exit(EXIT_FAILURE);
				}
				if (filter_parse(optarg, &ts->emm_filters[ts->emm_filters_num])) {
					ts->emm_filters_num++;
				} else {
					fprintf(stderr, "ERROR: Can't parse EMM filter: %s\n", optarg);
					exit(EXIT_FAILURE);
				}
				break;

			case 'X': // --ecm-pid
				ts->forced_ecm_pid = strtoul(optarg, NULL, 0) & 0x1fff;
				break;
			case 'v': // --ecm-only
				ts->process_emm = 0;
				ts->process_ecm = 1;
				ts->output_stream = 0;
				break;
			case 'H': // --ecm-report-time
				ts->ecm_report_interval = strtoul(optarg, NULL, 10);
				if (ts->ecm_report_interval > 86400)
					ts->ecm_report_interval = 86400;
				break;
			case 'G': // --ecm-irdeto-type
				ts->irdeto_ecm_idx = strtoul(optarg, NULL, 0);
				ts->irdeto_ecm_filter_type = IRDETO_FILTER_IDX;
				break;
			case '2': // --ecm-irdeto-chid
				ts->irdeto_ecm_chid = strtoul(optarg, NULL, 0);
				ts->irdeto_ecm_filter_type = IRDETO_FILTER_CHID;
				break;
			case 'K': // --ecm-no-log
				ts->ecm_cw_log = !ts->ecm_cw_log;
				break;
			case 'J': // --cw-warn-time
				ts->cw_warn_sec = strtoul(optarg, NULL, 10);
				if (ts->cw_warn_sec > 86400)
					ts->cw_warn_sec = 86400;
				ts->cw_last_warn= ts->cw_last_warn + ts->cw_warn_sec;
				break;
			case 'q': // --ecm-and-emm-only
				ts->process_emm = 1;
				ts->process_ecm = 1;
				ts->output_stream = 0;
				break;

			case 'D': // --debug
				ts->debug_level = atoi(optarg);
				if (ts->debug_level > 0)
					ts->pid_report = 1;
				break;
			case 'j': // --pid-report
				ts->pid_report = 1;
				break;
			case 'b': // --bench
				csa_benchmark();
				exit(EXIT_SUCCESS);

			case 'n': // --ecm-file
			case 'm': // --emm-file
				packet_from_file = 1;
				packet_buflen = file_hex2buf(optarg, packet_buf, sizeof(packet_buf));
				if (!packet_buflen) {
					fprintf(stderr, "ERROR: Can't init packet from file.\n");
					exit(1);
				}
				packet_type = j == 'n' ? ECM_MSG : EMM_MSG;
				break;

			case 'h': // --help
				show_help(ts);
				exit(EXIT_SUCCESS);

			case 'V': // --version
				printf("%s\n", program_id);
				exit(EXIT_SUCCESS);
		}
	}
	if (!ts->ident) {
		if (ts->syslog_active || ts->notify_program)
			ident_err = 1;
	}

	if (packet_from_file) {
		int err = 0;
		if (!ts->forced_caid) {
			fprintf(stderr, "ERROR: CAID was not set. Use --caid option.\n");
			err++;
		}
		if (!ts->forced_service_id) {
			fprintf(stderr, "ERROR: Service id was not set. Use --input-service option.\n");
			err++;
		}
		if (err)
			exit(EXIT_FAILURE);

		ts->threaded = 0;
		input_addr_err = 0;
		output_addr_err = 0;
		ts->input.type = FILE_IO;
		ts->input.fd = 0;
		ts->output.type = FILE_IO;
		ts->output.fd = 1;
		ts->pid_filter = 0;
		ts->process_ecm = 0;
		ts->process_emm = 0;
		ts->output_stream = 0;
		ts->camd.no_reconnect = 1;
		ts->camd.check_emm_errors = 1;
		ts->emm_filters_num = 0;
	}

	// Constant codeword is special. Disable conflicting options
	if (ts->camd.constant_codeword) {
		server_err = 0; // No server settings are required
		ts->process_ecm = 0;
		ts->process_emm = 0;
		ts->output_stream = 1;
	}

	if (ident_err || ca_err || server_err || input_addr_err || output_addr_err || ts->input.type == WTF_IO || ts->output.type == WTF_IO) {
		show_help(ts);
		if (ident_err)
			fprintf(stderr, "ERROR: Ident is not set, please use --ident option.\n");
		if (ca_err)
			fprintf(stderr, "ERROR: Requested CA system is unsupported.\n");
		if (server_err)
			fprintf(stderr, "ERROR: CAMD server address is not set or it is invalid.\n");
		if (input_addr_err)
			fprintf(stderr, "ERROR: Input address is invalid.\n");
		if (output_addr_err)
			fprintf(stderr, "ERROR: Output address is invalid.\n");
		exit(EXIT_FAILURE);
	}
	if (decode_hex_string(ts->camd.newcamd.hex_des_key, ts->camd.newcamd.bin_des_key, DESKEY_LENGTH) < 0) {
		fprintf(stderr, "ERROR: Invalid hex string for des key: %s\n", ts->camd.newcamd.hex_des_key);
		exit(EXIT_FAILURE);
	}
	if (ts->camd.ops.proto == CAMD_NEWCAMD && !port_set) {
		fprintf(stderr, "ERROR: CAMD server port is not set. Use --camd-server %s:xxxx to set the port.\n", ts->camd.hostname);
		exit(EXIT_FAILURE);
	}

	if (log_filename) {
		log_file = fopen(log_filename, "a");
		if (!log_file) {
			fprintf(stderr, "ERROR: Can't open log file %s: %s\n", log_filename, strerror(errno));
			exit(EXIT_FAILURE);
		}
	}

	if (ts->ident)
		ts_LOGf("Ident      : %s\n", ts->ident);
	if (ts->notify_program)
		ts_LOGf("Notify prg : %s\n", ts->notify_program);
	if (ts->pidfile)
		ts_LOGf("Daemonize  : %s pid file.\n", ts->pidfile);
	if (ts->syslog_active) {
		if (ts->syslog_remote)
			ts_LOGf("Syslog     : %s:%d\n", ts->syslog_host, ts->syslog_port);
		else
			ts_LOGf("Syslog     : enabled\n");
	} else {
		if (!packet_from_file)
			ts_LOGf("Syslog     : disabled\n");
	}

	if (!ts->camd.constant_codeword) {
		if (ts->forced_caid)
			ts->req_CA_sys = ts_get_CA_sys(ts->forced_caid);
		if (!ts->forced_caid)
			ts_LOGf("CA System  : %s\n", ts_get_CA_sys_txt(ts->req_CA_sys));
		else
			ts_LOGf("CA System  : %s | CAID: 0x%04x (%d)\n",
				ts_get_CA_sys_txt(ts->req_CA_sys),
				ts->forced_caid, ts->forced_caid);
	} else {
		char cw_even[64], cw_odd[64];
		ts_hex_dump_buf(cw_even, sizeof(cw_even), ts->key.cw    , 8, 0);
		ts_hex_dump_buf(cw_odd , sizeof(cw_odd ), ts->key.cw + 8, 8, 0);
		ts_LOGf("Constant CW: even = %s\n", cw_even);
		ts_LOGf("Constant CW: odd  = %s\n", cw_odd);
	}

	if (ts->input.type == NET_IO) {
		ts_LOGf("Input addr : %s://%s:%s/\n",
			ts->rtp_input ? "rtp" : "udp",
			ts->input.hostname, ts->input.service);
		ts_LOGf("Input src  : %s\n", inet_ntoa(ts->input.isrc));
		if (ts->input_buffer_time) {
			ts_LOGf("Input buff : %u ms\n", ts->input_buffer_time);
		}
	} else if (ts->input.type == FILE_IO) {
		if (!packet_from_file)
			ts_LOGf("Input file : %s\n", ts->input.fd == 0 ? "STDIN" : ts->input.fname);
	}
	if (ts->input_dump_filename) {
		ts->input_dump_file = fopen(ts->input_dump_filename, "w");
		if (ts->input_dump_file)
			ts_LOGf("Input dump : %s\n", ts->input_dump_filename);
		else
			ts_LOGf("Input dump : %s | ERROR: %s\n", ts->input_dump_filename, strerror(errno));
	}
	if (ts->forced_service_id)
		ts_LOGf("Service id : 0x%04x (%d)\n",
			ts->forced_service_id, ts->forced_service_id);
	if (ts->req_CA_sys == CA_IRDETO) {
		switch (ts->irdeto_ecm_filter_type) {
		case IRDETO_FILTER_IDX : ts_LOGf("Irdeto ECM : Index: 0x%02x (%d)\n", ts->irdeto_ecm_idx, ts->irdeto_ecm_idx); break;
		case IRDETO_FILTER_CHID: ts_LOGf("Irdeto ECM : CHID: 0x%04x (%d)\n", ts->irdeto_ecm_chid, ts->irdeto_ecm_chid); break;
		}
	}

	if (ts->output_stream) {
		if (ts->output.type == NET_IO) {
			ts_LOGf("Output addr: %s://%s:%s/\n",
				ts->rtp_output ? "rtp" : "udp",
				ts->output.hostname, ts->output.service);
			ts_LOGf("Output intf: %s (IPv6 intf index:%d)\n",
				inet_ntoa(ts->output.intf), ts->output.v6_if_index);
			ts_LOGf("Output ttl : %d\n", ts->output.ttl);
			if (ts->output.tos > -1)
				ts_LOGf("Output TOS : %u (0x%02x)\n", ts->output.tos, ts->output.tos);
			if (ts->rtp_output) {
				ts_LOGf("RTP SSRC   : %u (0x%04x)\n",
					ts->rtp_ssrc, ts->rtp_ssrc);
				// It is recommended that RTP seqnum starts with random number
				RAND_bytes((unsigned char *)&(ts->rtp_seqnum), 2);
			}
		} else if (ts->output.type == FILE_IO) {
			ts_LOGf("Output file: %s\n", ts->output.fd == 1 ? "STDOUT" : ts->output.fname);
		}
		ts_LOGf("Out filter : %s (%s)%s\n",
			ts->pid_filter ? "enabled" : "disabled",
			ts->pid_filter ? "output only service related PIDs" : "output everything",
			ts->no_output_on_error ? " (No output on CW error)" : ""
		);
		if (ts->pid_filter) {
			if (ts->nit_passthrough)
				ts_LOGf("Out filter : Pass through NIT.\n");
			if (ts->eit_passthrough)
				ts_LOGf("Out filter : Pass through EIT (EPG).\n");
			if (ts->tdt_passthrough)
				ts_LOGf("Out filter : Pass through TDT/TOT.\n");
		}
		ts_LOGf("TS discont : %s\n", ts->ts_discont ? "report" : "ignore");
		ts->threaded = !(ts->input.type == FILE_IO && ts->input.fd != 0);
		ts_LOGf("Decoding   : %s\n", ts->threaded ? "threaded" : "single thread");
	} else {
		ts_LOGf("Decoding   : disabled\n");
	}

	if (!ts->camd.constant_codeword) {
		ts_LOGf("CAMD proto : %s\n", ts->camd.ops.ident);
		ts_LOGf("CAMD addr  : %s:%s%s\n", ts->camd.hostname, ts->camd.service,
			ai_family == AF_INET  ? " (IPv4 only)" :
			ai_family == AF_INET6 ? " (IPv6 only)" :
			" (IPv4/IPv6)"
		);
		ts_LOGf("CAMD user  : %s\n", ts->camd.user);
		ts_LOGf("CAMD pass  : %s\n", ts->camd.pass);
		if (ts->camd.ops.proto == CAMD_NEWCAMD)
			ts_LOGf("CAMD deskey: %s\n", ts->camd.newcamd.hex_des_key);
	}

	if (!packet_from_file)
		ts_LOGf("EMM process: %s\n", ts->process_emm ? "Yes" : "No");

	if (ts->process_emm) {
		if (ts->forced_emm_pid)
			ts_LOGf("EMM pid    : 0x%04x (%d)\n", ts->forced_emm_pid, ts->forced_emm_pid);

		if (ts->emm_report_interval)
			ts_LOGf("EMM report : %d sec\n", ts->emm_report_interval);
		else
			ts_LOGf("EMM report : disabled\n");

		for (i = 0; i < ts->emm_filters_num; i++) {
			char tmp[512];
			filter_dump(&ts->emm_filters[i], tmp, sizeof(tmp));
			ts_LOGf("EMM filter : [%2d] %s\n", i + 1,  tmp);
		}
	}

	if (!packet_from_file)
		ts_LOGf("ECM process: %s\n", ts->process_ecm ? "Yes" : "No");

	if (ts->process_ecm) {
		if (ts->forced_ecm_pid)
			ts_LOGf("ECM pid    : 0x%04x (%d)\n", ts->forced_ecm_pid, ts->forced_ecm_pid);

		if (ts->ecm_report_interval)
			ts_LOGf("ECM report : %d sec\n", ts->emm_report_interval);
		else
			ts_LOGf("ECM report : disabled\n");

		if (ts->cw_warn_sec)
			ts_LOGf("CW warning : %d sec\n", ts->cw_warn_sec);
		else
			ts_LOGf("CW warning : disabled\n");

		if (!ts->ecm_cw_log)
			ts_LOGf("ECM/CW log : disabled\n");
	}

	if (ts->ident) {
		int len = strlen(ts->ident);
		for (i = 0; i < len; i++) {
			if (ts->ident[i] == '/')
				ts->ident[i] = '-';
		}
	}
}
Пример #5
0
int
main (int argc,
      char **argv,
      char **envp)
{
  cache_entry *cache_rules = NULL;
  lf_file_references file_references = lf_include_references;
  decode_table *decode_rules = NULL;
  insn_table *isa = NULL;
  gen_table *gen = NULL;
  char *real_file_name = NULL;
  int is_header = 0;
  int ch;
  lf *standard_out = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "igen");

  INIT_OPTIONS ();

  if (argc == 1)
    {
      printf ("Usage:\n");
      printf ("\n");
      printf ("  igen <config-opts> ... <input-opts>... <output-opts>...\n");
      printf ("\n");
      printf ("Config options:\n");
      printf ("\n");
      printf ("  -B <bit-size>\n");
      printf ("\t Set the number of bits in an instruction (depreciated).\n");
      printf ("\t This option can now be set directly in the instruction table.\n");
      printf ("\n");
      printf ("  -D <data-structure>\n");
      printf ("\t Dump the specified data structure to stdout. Valid structures include:\n");
      printf ("\t processor-names - list the names of all the processors (models)\n");
      printf ("\n");
      printf ("  -F <filter-list>\n");
      printf ("\t Filter out any instructions with a non-empty flags field that contains\n");
      printf ("\t a flag not listed in the <filter-list>.\n");
      printf ("\n");
      printf ("  -H <high-bit>\n");
      printf ("\t Set the number of the high (most significant) instruction bit (depreciated).\n");
      printf ("\t This option can now be set directly in the instruction table.\n");
      printf ("\n");
      printf ("  -I <directory>\n");
      printf ("\t Add <directory> to the list of directories searched when opening a file\n");
      printf ("\n");
      printf ("  -M <model-list>\n");
      printf ("\t Filter out any instructions that do not support at least one of the listed\n");
      printf ("\t models (An instructions with no model information is considered to support\n");
      printf ("\t all models.).\n");
      printf ("\n");
      printf ("  -N <nr-cpus>\n");
      printf ("\t Generate a simulator supporting <nr-cpus>\n");
      printf ("\t Specify `-N 0' to disable generation of the SMP. Specifying `-N 1' will\n");
      printf ("\t still generate an SMP enabled simulator but will only support one CPU.\n");
      printf ("\n");
      printf ("  -T <mechanism>\n");
      printf ("\t Override the decode mechanism specified by the decode rules\n");
      printf ("\n");
      printf ("  -P <prefix>\n");
      printf ("\t Prepend global names (except itable) with the string <prefix>.\n");
      printf ("\t Specify -P <module>=<prefix> to set a specific <module>'s prefix.\n");
      printf ("\n");
      printf ("  -S <suffix>\n");
      printf ("\t Replace a global name (suffix) (except itable) with the string <suffix>.\n");
      printf ("\t Specify -S <module>=<suffix> to change a specific <module>'s name (suffix).\n");
      printf ("\n");
      printf ("  -Werror\n");
      printf ("\t Make warnings errors\n");
      printf ("  -Wnodiscard\n");
      printf ("\t Suppress warnings about discarded functions and instructions\n");
      printf ("  -Wnowidth\n");
      printf ("\t Suppress warnings about instructions with invalid widths\n");
      printf ("  -Wnounimplemented\n");
      printf ("\t Suppress warnings about unimplemented instructions\n");
      printf ("\n");
      printf ("  -G [!]<gen-option>\n");
      printf ("\t Any of the following options:\n");
      printf ("\n");
      printf ("\t decode-duplicate       - Override the decode rules, forcing the duplication of\n");
      printf ("\t                          semantic functions\n");
      printf ("\t decode-combine         - Combine any duplicated entries within a table\n");
      printf ("\t decode-zero-reserved   - Override the decode rules, forcing reserved bits to be\n");
      printf ("\t                          treated as zero.\n");
      printf ("\t decode-switch-is-goto  - Overfide the padded-switch code type as a goto-switch\n");
      printf ("\n");
      printf ("\t gen-conditional-issue  - conditionally issue each instruction\n");
      printf ("\t gen-delayed-branch     - need both cia and nia passed around\n");
      printf ("\t gen-direct-access      - use #defines to directly access values\n");
      printf ("\t gen-zero-r<N>          - arch assumes GPR(<N>) == 0, keep it that way\n");
      printf ("\t gen-icache[=<N>        - generate an instruction cracking cache of size <N>\n");
      printf ("\t                          Default size is %d\n", options.gen.icache_size);
      printf ("\t gen-insn-in-icache     - save original instruction when cracking\n");
      printf ("\t gen-multi-sim[=MODEL]  - generate multiple simulators - one per model\n");
      printf ("\t                          If specified MODEL is made the default architecture.\n");
      printf ("\t                          By default, a single simulator that will\n");
      printf ("\t                          execute any instruction is generated\n");
      printf ("\t gen-multi-word         - generate code allowing for multi-word insns\n");
      printf ("\t gen-semantic-icache    - include semantic code in cracking functions\n");
      printf ("\t gen-slot-verification  - perform slot verification as part of decode\n");
      printf ("\t gen-nia-invalid        - NIA defaults to nia_invalid\n");
      printf ("\t gen-nia-void           - do not compute/return NIA\n");
      printf ("\n");
      printf ("\t trace-combine          - report combined entries a rule application\n");
      printf ("\t trace-entries          - report entries after a rules application\n");
      printf ("\t trace-rule-rejection   - report each rule as rejected\n");
      printf ("\t trace-rule-selection   - report each rule as selected\n");
      printf ("\t trace-insn-insertion   - report each instruction as it is inserted into a decode table\n");
      printf ("\t trace-rule-expansion   - report each instruction as it is expanded (before insertion into a decode table)\n");
      printf ("\t trace-all              - enable all trace options\n");
      printf ("\n");
      printf ("\t field-widths           - instruction formats specify widths (depreciated)\n");
      printf ("\t                          By default, an instruction format specifies bit\n");
      printf ("\t                          positions\n");
      printf ("\t                          This option can now be set directly in the\n");
      printf ("\t                          instruction table\n");
      printf ("\t jumps                  - use jumps instead of function calls\n");
      printf ("\t omit-line-numbers      - do not include line number information in the output\n");
      printf ("\n");
      printf ("Input options:\n");
      printf ("\n");
      printf ("  -k <cache-rules> (depreciated)\n");
      printf ("  -o <decode-rules>\n");
      printf ("  -i <instruction-table>\n");
      printf ("\n");
      printf ("Output options:\n");
      printf ("\n");
      printf ("  -x                    Perform expansion (required)\n");
      printf ("  -n <real-name>        Specify the real name of the next output file\n"); 
      printf ("  -h 		       Generate the header (.h) file rather than the body (.c)\n");
      printf ("  -c <output-file>      output icache\n");
      printf ("  -d <output-file>      output idecode\n");
      printf ("  -e <output-file>      output engine\n");
      printf ("  -f <output-file>      output support functions\n");
      printf ("  -m <output-file>      output model\n");
      printf ("  -r <output-file>      output multi-sim run\n");
      printf ("  -s <output-file>      output schematic\n");
      printf ("  -t <output-file>      output itable\n");
    }
  
  while ((ch = getopt(argc, argv,
		      "B:D:F:G:H:I:M:N:P:T:W:o:k:i:n:hc:d:e:m:r:s:t:f:x"))
	 != -1)
    {
      fprintf (stderr, "  -%c ", ch);
      if (optarg)
	fprintf (stderr, "%s ", optarg);
      fprintf (stderr, "\\\n");
      
      switch(ch)
	{
	  
	case 'M':
	  filter_parse (&options.model_filter, optarg);
	  break;

	case 'D':
	  if (strcmp (optarg, "processor-names"))
	    {
	      char *processor;
	      for (processor = filter_next (options.model_filter, "");
		   processor != NULL;
		   processor = filter_next (options.model_filter, processor))
		lf_printf (standard_out, "%s\n", processor);
	    }
	  else
	    error (NULL, "Unknown data structure %s, not dumped\n", optarg);
	  break;

	case 'F':
	  filter_parse (&options.flags_filter, optarg);
	  break;
	  
	case 'I':
	  {
	    table_include **dir = &options.include;
	    while ((*dir) != NULL)
	      dir = &(*dir)->next;
	    (*dir) = ZALLOC (table_include);
	    (*dir)->dir = strdup (optarg);
	  }
	  break;
	  
	case 'B':
	  options.insn_bit_size = a2i (optarg);
	  if (options.insn_bit_size <= 0
	      || options.insn_bit_size > max_insn_bit_size)
	    {
	      error (NULL, "Instruction bitsize must be in range 1..%d\n",
		     max_insn_bit_size);
	    }
	  if (options.hi_bit_nr != options.insn_bit_size - 1
	      && options.hi_bit_nr != 0)
	    {
	      error (NULL, "Conflict betweem hi-bit-nr and insn-bit-size\n");
	    }
	  break;
	  
	case 'H':
	  options.hi_bit_nr = a2i (optarg);
	  if (options.hi_bit_nr != options.insn_bit_size - 1
	      && options.hi_bit_nr != 0)
	    {
	      error (NULL, "Conflict between hi-bit-nr and insn-bit-size\n");
	    }
	  break;
	  
	case 'N':
	  options.gen.smp = a2i (optarg);
	  break;
	  
	case 'P':
	case 'S':
	  {
	    igen_module *names;
	    igen_name *name;
	    char *chp;
	    chp = strchr (optarg, '=');
	    if (chp == NULL)
	      {
		names = &options.module.global;
		chp = optarg;
	      }
	    else
	      {
		chp = chp + 1; /* skip `=' */
		names = NULL;
		if (strncmp (optarg, "global=", chp - optarg) == 0)
		  {
		    names = &options.module.global;
		  }
		if (strncmp (optarg, "engine=", chp - optarg) == 0)
		  {
		    names = &options.module.engine;
		  }
		if (strncmp (optarg, "icache=", chp - optarg) == 0)
		  {
		    names = &options.module.icache;
		  }
		if (strncmp (optarg, "idecode=", chp - optarg) == 0)
		  {
		    names = &options.module.idecode;
		  }
		if (strncmp (optarg, "itable=", chp - optarg) == 0)
		  {
		    names = &options.module.itable;
		  }
		if (strncmp (optarg, "semantics=", chp - optarg) == 0)
		  {
		    names = &options.module.semantics;
		  }
		if (strncmp (optarg, "support=", chp - optarg) == 0)
		  {
		    names = &options.module.support;
		  }
		if (names == NULL)
		  {
		    error (NULL, "Prefix `%s' unreconized\n", optarg);
		  }
	      }
	    switch (ch)
	      {
	      case 'P':
		name = &names->prefix;
		break;
	      case 'S':
		name = &names->suffix;
		break;
	      }
	    name->u = strdup (chp);
	    name->l = strdup (chp);
	    chp = name->u;
	    while (*chp) {
	      if (islower(*chp))
		*chp = toupper(*chp);
	      chp++;
	    }
	    if (name == &options.module.global.prefix)
	      {
		options.module.engine.prefix = options.module.global.prefix;
		options.module.icache.prefix = options.module.global.prefix;
		options.module.idecode.prefix = options.module.global.prefix;
		/* options.module.itable.prefix = options.module.global.prefix; */
		options.module.semantics.prefix = options.module.global.prefix;
		options.module.support.prefix = options.module.global.prefix;
	      }
	    if (name == &options.module.global.suffix)
	      {
		options.module.engine.suffix = options.module.global.suffix;
		options.module.icache.suffix = options.module.global.suffix;
		options.module.idecode.suffix = options.module.global.suffix;
		/* options.module.itable.suffix = options.module.global.suffix; */
		options.module.semantics.suffix = options.module.global.suffix;
		options.module.support.suffix = options.module.global.suffix;
	      }
	    break;
	  }
	
	case 'W':
	  {
	    if (strcmp (optarg, "error") == 0)
	      options.warning = error;
	    else if (strcmp (optarg, "nodiscard") == 0)
	      options.warn.discard = 0;
	    else if (strcmp (optarg, "discard") == 0)
	      options.warn.discard = 1;
	    else if (strcmp (optarg, "nowidth") == 0)
	      options.warn.width = 0;
	    else if (strcmp (optarg, "width") == 0)
	      options.warn.width = 1;
	    else if (strcmp (optarg, "nounimplemented") == 0)
	      options.warn.unimplemented = 0;
	    else if (strcmp (optarg, "unimplemented") == 0)
	      options.warn.unimplemented = 1;
	    else
	      error (NULL, "Unknown -W argument `%s'\n", optarg);
	    break;
	  }


	case 'G':
	  {
	    int enable_p;
	    char *argp;
	    if (strncmp (optarg, "no-", strlen ("no-")) == 0)
	      {
		argp = optarg + strlen ("no-");
		enable_p = 0;
	      }
	    else if (strncmp (optarg, "!", strlen ("!")) == 0)
	      {
		argp = optarg + strlen ("no-");
		enable_p = 0;
	      }
	    else
	      {
		argp = optarg;
		enable_p = 1;
	      }
	    if (strcmp (argp, "decode-duplicate") == 0)
	      {
		options.decode.duplicate = enable_p;
	      }
	    else if (strcmp (argp, "decode-combine") == 0)
	      {
		options.decode.combine = enable_p;
	      }
	    else if (strcmp (argp, "decode-zero-reserved") == 0)
	      {
		options.decode.zero_reserved = enable_p;
	      }
	    
	    else if (strcmp (argp, "gen-conditional-issue") == 0)
	      {
		options.gen.conditional_issue = enable_p;
	      }
	    else if (strcmp (argp, "conditional-issue") == 0)
	      {
		options.gen.conditional_issue = enable_p;
		options.warning (NULL, "Option conditional-issue replaced by gen-conditional-issue\n");
	      }
	    else if (strcmp (argp, "gen-delayed-branch") == 0)
	      {
		options.gen.delayed_branch = enable_p;
	      }
	    else if (strcmp (argp, "delayed-branch") == 0)
	      {
		options.gen.delayed_branch = enable_p;
		options.warning (NULL, "Option delayed-branch replaced by gen-delayed-branch\n");
	      }
	    else if (strcmp (argp, "gen-direct-access") == 0)
	      {
		options.gen.direct_access = enable_p;
	      }
	    else if (strcmp (argp, "direct-access") == 0)
	      {
		options.gen.direct_access = enable_p;
		options.warning (NULL, "Option direct-access replaced by gen-direct-access\n");
	      }
	    else if (strncmp (argp, "gen-zero-r", strlen ("gen-zero-r")) == 0)
	      {
		options.gen.zero_reg = enable_p;
		options.gen.zero_reg_nr = atoi (argp + strlen ("gen-zero-r"));
	      }
	    else if (strncmp (argp, "zero-r", strlen ("zero-r")) == 0)
	      {
		options.gen.zero_reg = enable_p;
		options.gen.zero_reg_nr = atoi (argp + strlen ("zero-r"));
		options.warning (NULL, "Option zero-r<N> replaced by gen-zero-r<N>\n");
	      }
	    else if (strncmp (argp, "gen-icache", strlen ("gen-icache")) == 0)
	      {
		switch (argp[strlen ("gen-icache")])
		  {
		  case '=':
		    options.gen.icache_size = atoi (argp + strlen ("gen-icache") + 1);
		    options.gen.icache = enable_p;
		    break;
		  case '\0':
		    options.gen.icache = enable_p;
		    break;
		  default:
		    error (NULL, "Expecting -Ggen-icache or -Ggen-icache=<N>\n");
		  }
	      }
	    else if (strcmp (argp, "gen-insn-in-icache") == 0)
	      {
		options.gen.insn_in_icache = enable_p;
	      }
	    else if (strncmp (argp, "gen-multi-sim", strlen ("gen-multi-sim")) == 0)
	      {
		char *arg = &argp[strlen ("gen-multi-sim")];
		switch (arg[0])
		  {
		  case '=':
		    options.gen.multi_sim = enable_p;
		    options.gen.default_model = arg + 1;
		    if (! filter_is_member (options.model_filter, options.gen.default_model))
		      error (NULL, "multi-sim model %s unknown\n", options.gen.default_model);
		    break;
		  case '\0':
		    options.gen.multi_sim = enable_p;
		    options.gen.default_model = NULL;
		    break;
		  default:
		    error (NULL, "Expecting -Ggen-multi-sim or -Ggen-multi-sim=<MODEL>\n");
		    break;
		  }
	      }
	    else if (strcmp (argp, "gen-multi-word") == 0)
	      {
		options.gen.multi_word = enable_p;
	      }
	    else if (strcmp (argp, "gen-semantic-icache") == 0)
	      {
		options.gen.semantic_icache = enable_p;
	      }
	    else if (strcmp (argp, "gen-slot-verification") == 0)
	      {
		options.gen.slot_verification = enable_p;
	      }
	    else if (strcmp (argp, "verify-slot") == 0)
	      {
		options.gen.slot_verification = enable_p;
		options.warning (NULL, "Option verify-slot replaced by gen-slot-verification\n");
	      }
	    else if (strcmp (argp, "gen-nia-invalid") == 0)
	      {
		options.gen.nia = nia_is_invalid;
	      }
	    else if (strcmp (argp, "default-nia-minus-one") == 0)
	      {
		options.gen.nia = nia_is_invalid;
		options.warning (NULL, "Option default-nia-minus-one replaced by gen-nia-invalid\n");
	      }
	    else if (strcmp (argp, "gen-nia-void") == 0)
	      {
		options.gen.nia = nia_is_void;
	      }
	    else if (strcmp (argp, "trace-all") == 0)
	      {
		memset (&options.trace, enable_p, sizeof (options.trace));
	      }
	    else if (strcmp (argp, "trace-combine") == 0)
	      {
		options.trace.combine = enable_p;
	      }
	    else if (strcmp (argp, "trace-entries") == 0)
	      {
		options.trace.entries = enable_p;
	      }
	    else if (strcmp (argp, "trace-rule-rejection") == 0)
	      {
		options.trace.rule_rejection = enable_p;
	      }
	    else if (strcmp (argp, "trace-rule-selection") == 0)
	      {
		options.trace.rule_selection = enable_p;
	      }
	    else if (strcmp (argp, "trace-insn-insertion") == 0)
	      {
		options.trace.insn_insertion = enable_p;
	      }
	    else if (strcmp (argp, "trace-insn-expansion") == 0)
	      {
		options.trace.insn_expansion = enable_p;
	      }
	    else if (strcmp (argp, "jumps") == 0)
	      {
		options.gen.code = generate_jumps;
	      }
	    else if (strcmp (argp, "field-widths") == 0)
	      {
		options.insn_specifying_widths = enable_p;
	      }
	    else if (strcmp (argp, "omit-line-numbers") == 0)
	      {
		file_references = lf_omit_references;
	      }
	    else
	      {
		error (NULL, "Unknown option %s\n", optarg);
	      }
	    break;
	  }
	
	case 'i':
	  isa = load_insn_table (optarg, cache_rules);
	  if (isa->illegal_insn == NULL)
	    error (NULL, "illegal-instruction missing from insn table\n");
	  break;

	case 'x':
	  gen = do_gen (isa, decode_rules);
	  break;

	case 'o':
	  decode_rules = load_decode_table (optarg);
	  break;

	case 'k':
	  if (isa != NULL)
	    error (NULL, "Cache file must appear before the insn file\n");
	  cache_rules = load_cache_table (optarg);
	  break;

	case 'n':
	  real_file_name = strdup(optarg);
	  break;

	case 'h':
	  is_header = 1;
	  break;
	  
	case 'c':
	case 'd':
	case 'e':
	case 'f':
	case 'm':
	case 'r':
	case 's':
	case 't':
	  {
	    lf *file = lf_open(optarg, real_file_name, file_references,
			       (is_header ? lf_is_h : lf_is_c),
			       argv[0]);
	    if (gen == NULL && ch != 't' && ch != 'm' && ch != 'f')
	      {
		options.warning (NULL, "Explicitly generate tables with -x option\n");
		gen = do_gen (isa, decode_rules);
	      }
	    lf_print__file_start(file);
	    switch (ch)
	      {
	      case 'm':
		if (is_header)
		  gen_model_h (file, isa);
		else
		  gen_model_c (file, isa);
		break;
	      case 't':
		if (is_header)
		  gen_itable_h (file, isa);
		else
		  gen_itable_c (file, isa);
		break;
	      case 'f':
		if (is_header)
		  gen_support_h (file, isa);
		else
		  gen_support_c (file, isa);
		break;
	      case 'r':
		if (is_header)
		  options.warning (NULL, "-hr option ignored\n");
		else
		  gen_run_c (file, gen);
		break;
	      case 's':
		if(is_header)
		  gen_semantics_h (file, gen->semantics, isa->max_nr_words);
		else
		  gen_semantics_c (file, gen->semantics, isa->caches);
		break;
	      case 'd':
		if (is_header)
		  gen_idecode_h (file, gen, isa, cache_rules);
		else
		  gen_idecode_c (file, gen, isa, cache_rules);
		break;
	      case 'e':
		if (is_header)
		  gen_engine_h (file, gen, isa, cache_rules);
		else
		  gen_engine_c (file, gen, isa, cache_rules);
		break;
	      case 'c':
		if (is_header)
		  gen_icache_h (file,
				gen->semantics,
				isa->functions,
				isa->max_nr_words);
		else
		  gen_icache_c (file,
				gen->semantics,
				isa->functions,
				cache_rules);
		break;
	      }
	    lf_print__file_finish(file);
	    lf_close(file);
	    is_header = 0;
	  }
	real_file_name = NULL;
	break;
	default:
	  ERROR ("Bad switch");
	}
    }
  return (0);
}
Пример #6
0
struct client_t *accept_client_for_listener(struct listen_t *l, int fd, char *addr_s, union sockaddr_u *sa, unsigned addr_len)
{
	struct client_t *c;
	char *s;
	int i;
	union sockaddr_u sa_loc; /* local address */
	socklen_t addr_len_loc = sizeof(sa_loc);
	
	c = client_alloc();
	if (!c)
		return NULL;
		
	c->fd    = fd;
	c->listener_id = l->listener_id;
	c->addr  = *sa;
	c->ai_protocol = l->ai_protocol;
	c->portnum = l->portnum;
	c->hidden  = l->hidden;
	c->flags   = l->client_flags;
	c->udpclient = client_udp_find(udpclients, sa->sa.sa_family, l->portnum);
	c->portaccount = l->portaccount;
	c->last_read = tick; /* not simulated time */
	inbound_connects_account(1, c->portaccount); /* account all ports + port-specifics */
	
	/* text format of client's IP address + port */
	strncpy(c->addr_rem, addr_s, sizeof(c->addr_rem));
	c->addr_rem[sizeof(c->addr_rem)-1] = 0;

	/* hex format of client's IP address + port */
	s = hexsockaddr( &sa->sa, addr_len );
	strncpy(c->addr_hex, s, sizeof(c->addr_hex));
	c->addr_hex[sizeof(c->addr_hex)-1] = 0;
	hfree(s);

	/* text format of servers' connected IP address + port */
	if (getsockname(fd, &sa_loc.sa, &addr_len_loc) == 0) { /* Fails very rarely.. */
		if (addr_len_loc > sizeof(sa_loc))
			hlog(LOG_ERR, "accept_client_for_listener: getsockname for client %s truncated local address of %d to %d bytes", c->addr_rem, addr_len_loc, sizeof(sa_loc));
		/* present my socket end address as a malloced string... */
		s = strsockaddr( &sa_loc.sa, addr_len_loc );
	} else {
		s = hstrdup( l->addr_s ); /* Server's bound IP address */
		hlog(LOG_ERR, "accept_client_for_listener: getsockname for client %s failed: %s (using '%s' instead)", c->addr_rem, strerror(errno), s);
	}
	strncpy(c->addr_loc, s, sizeof(c->addr_loc));
	c->addr_loc[sizeof(c->addr_loc)-1] = 0;
	hfree(s);

	/* apply predefined filters */
	for (i = 0; i < (sizeof(l->filters)/sizeof(l->filters[0])); ++i) {
		if (l->filters[i]) {
			if (filter_parse(c, l->filters[i], 0) < 0) { /* system filters */
				hlog(LOG_ERR, "Bad system filter definition: %s", l->filters[i]);
			}
		}
	}
	if (l->filter_s) {
		strncpy(c->filter_s, l->filter_s, sizeof(c->filter_s));
		c->filter_s[FILTER_S_SIZE-1] = 0;
	}
	
	return c;
}
Пример #7
0
static int accept_liveupgrade_single(cJSON *client, int *rxerr_map, int rxerr_map_len)
{
	cJSON *fd, *listener_id, *username, *time_connect, *tick_connect;
	cJSON *state;
	cJSON *addr_loc;
	cJSON *udp_port;
	cJSON *app_name, *app_version;
	cJSON *verified;
	cJSON *obuf_q;
	cJSON *bytes_rx, *bytes_tx;
	cJSON *pkts_rx, *pkts_tx, *pkts_ign;
	cJSON *rx_errs;
	cJSON *filter;
	cJSON *ibuf, *obuf;
	cJSON *client_heard;
	cJSON *lat, *lng;
	unsigned addr_len;
	union sockaddr_u sa;
	char *argv[256];
	int i, argc;
	const char *username_s = "unknown";
	
	/* get username first, so we can log it later */
	username = accept_liveupgrade_cJSON_get(client, "username", cJSON_String, username_s);
	if (username)
		username_s = username->valuestring;
	
	fd = accept_liveupgrade_cJSON_get(client, "fd", cJSON_Number, username_s);
	int fd_i = -1;
	if (fd)
		fd_i = fd->valueint;
		
	if (fd_i < 0) {
		hlog(LOG_INFO, "Live upgrade: Client '%s' has negative fd %d, ignoring (corepeer?)", username_s, fd_i);
		return -1;
	}
	
	listener_id = accept_liveupgrade_cJSON_get(client, "listener_id", cJSON_Number, username_s);
	state = accept_liveupgrade_cJSON_get(client, "state", cJSON_String, username_s);
	time_connect = accept_liveupgrade_cJSON_get(client, "t_connect", cJSON_Number, username_s);
	addr_loc = accept_liveupgrade_cJSON_get(client, "addr_loc", cJSON_String, username_s);
	app_name = accept_liveupgrade_cJSON_get(client, "app_name", cJSON_String, username_s);
	app_version = accept_liveupgrade_cJSON_get(client, "app_version", cJSON_String, username_s);
	verified = accept_liveupgrade_cJSON_get(client, "verified", cJSON_Number, username_s);
	obuf_q = accept_liveupgrade_cJSON_get(client, "obuf_q", cJSON_Number, username_s);
	bytes_rx = accept_liveupgrade_cJSON_get(client, "bytes_rx", cJSON_Number, username_s);
	bytes_tx = accept_liveupgrade_cJSON_get(client, "bytes_tx", cJSON_Number, username_s);
	pkts_rx = accept_liveupgrade_cJSON_get(client, "pkts_rx", cJSON_Number, username_s);
	pkts_tx = accept_liveupgrade_cJSON_get(client, "pkts_tx", cJSON_Number, username_s);
	pkts_ign = accept_liveupgrade_cJSON_get(client, "pkts_ign", cJSON_Number, username_s);
	rx_errs = accept_liveupgrade_cJSON_get(client, "rx_errs", cJSON_Array, username_s);
	filter = accept_liveupgrade_cJSON_get(client, "filter", cJSON_String, username_s);
	
	/* optional */
	tick_connect = cJSON_GetObjectItem(client, "t_connect_tick");
	udp_port = cJSON_GetObjectItem(client, "udp_port");
	ibuf = cJSON_GetObjectItem(client, "ibuf");
	obuf = cJSON_GetObjectItem(client, "obuf");
	client_heard = cJSON_GetObjectItem(client, "client_heard");
	lat = cJSON_GetObjectItem(client, "lat");
	lng = cJSON_GetObjectItem(client, "lng");
	
	if (!(
		(fd)
		&& (listener_id)
		&& (state)
		&& (username)
		&& (time_connect)
		&& (addr_loc)
		&& (app_name)
		&& (app_version)
		&& (verified)
		&& (obuf_q)
		&& (bytes_rx)
		&& (bytes_tx)
		&& (pkts_rx)
		&& (pkts_tx)
		&& (pkts_ign)
		&& (rx_errs)
		&& (filter)
		)) {
			hlog(LOG_ERR, "Live upgrade: Fields missing from client JSON, discarding client fd %d", fd_i);
			if (fd_i >= 0)
				close(fd_i);
			return -1;
	}
	
	hlog(LOG_DEBUG, "Old client on fd %d: %s", fd->valueint, username->valuestring);
	
	/* fetch peer address from the fd instead of parsing it from text */
	addr_len = sizeof(sa);
	if (getpeername(fd->valueint, &sa.sa, &addr_len) != 0) {
		/* Sometimes clients disconnect during upgrade, especially on slow RPi servers... */
		if (errno == ENOTCONN)
			hlog(LOG_INFO, "Live upgrade: Client %s on fd %d has disconnected during upgrade (%s)",
				username->valuestring, fd->valueint, strerror(errno));
		else
			hlog(LOG_ERR, "Live upgrade: getpeername client fd %d failed: %s", fd->valueint, strerror(errno));
		close(fd->valueint);
		return -1;
	}
	
	/* convert client address to string */
	char *client_addr_s = strsockaddr( &sa.sa, addr_len );
	
	/* find the right listener for this client, for configuration and accounting */
	struct listen_t *l = liveupgrade_find_listener(listener_id->valueint);
	if (!l) {
		hlog(LOG_INFO, "Live upgrade: Listener has been removed for fd %d (%s - local %s): disconnecting %s",
			fd->valueint, client_addr_s, addr_loc->valuestring, username->valuestring);
		close(fd->valueint);
		hfree(client_addr_s);
		return -1;
	}
	
	struct client_t *c = accept_client_for_listener(l, fd->valueint, client_addr_s, &sa, addr_len);
	if (!c) {
		hlog(LOG_ERR, "Live upgrade - client_alloc returned NULL, too many clients. Denied client %s on fd %d from %s",
			username->valuestring, fd->valueint, client_addr_s);
		close(fd->valueint);
		hfree(client_addr_s);
		return -1;
	}
	
	hfree(client_addr_s);
	
	if (strcmp(state->valuestring, "connected") == 0) {
		c->state   = CSTATE_CONNECTED;
		c->handler_line_in = &incoming_handler;
		strncpy(c->username, username->valuestring, sizeof(c->username));
		c->username[sizeof(c->username)-1] = 0;
		c->username_len = strlen(c->username);
	} else if (strcmp(state->valuestring, "login") == 0) {
		c->state   = CSTATE_LOGIN;
		c->handler_line_in = &login_handler;
	} else {
		hlog(LOG_ERR, "Live upgrade: Client %s is in invalid state '%s' (fd %d)", l->addr_s, state->valuestring, l->fd);
		goto err;
	}
	/* distribute keepalive intervals for the existing old clients
	 * but send them rather sooner than later */
	// coverity[dont_call]  // squelch warning: not security sensitive use of random(): load distribution
	c->keepalive = tick + (random() % (keepalive_interval/2));
	/* distribute cleanup intervals over the next 2 minutes */
	// coverity[dont_call]  // squelch warning: not security sensitive use of random(): load distribution
	c->cleanup = tick + (random() % 120);
	
	c->connect_time = time_connect->valueint;
	/* live upgrade / backward compatibility: upgrading from <= 1.8.2 requires the 'else' path' */
	if (tick_connect && tick_connect->type == cJSON_Number)
		c->connect_tick = tick_connect->valueint;
	else /* convert to monotonic time */
		c->connect_tick = tick - (now - c->connect_time);
	
	c->validated = verified->valueint;
	c->localaccount.rxbytes = bytes_rx->valuedouble;
	c->localaccount.txbytes = bytes_tx->valuedouble;
	c->localaccount.rxpackets = pkts_rx->valuedouble;
	c->localaccount.txpackets = pkts_tx->valuedouble;
	c->localaccount.rxdrops = pkts_ign->valuedouble;
	
	login_set_app_name(c, app_name->valuestring, app_version->valuestring);
	
	// handle client's filter setting
	if (c->flags & CLFLAGS_USERFILTEROK && (filter) && (filter->valuestring) && *(filter->valuestring)) {
		// archive a copy of the filters, for status display
		strncpy(c->filter_s, filter->valuestring, FILTER_S_SIZE);
		c->filter_s[FILTER_S_SIZE-1] = 0;
		sanitize_ascii_string(c->filter_s);
		
		char *f = hstrdup(filter->valuestring);
		argc = parse_args(argv, f);
		for (i = 0; i < argc; ++i) {
			filter_parse(c, argv[i], 1);
		}
		hfree(f);
	}
	
	// set up UDP downstream if necessary
	if (udp_port && udp_port->type == cJSON_Number && udp_port->valueint > 1024 && udp_port->valueint < 65536) {
		if (login_setup_udp_feed(c, udp_port->valueint) != 0) {
			hlog(LOG_DEBUG, "%s/%s: Requested UDP on client port with no UDP configured", c->addr_rem, c->username);
		}
	}
	
	// fill up ibuf
	if (ibuf && ibuf->type == cJSON_String && ibuf->valuestring) {
		int l = hex_decode(c->ibuf, c->ibuf_size, ibuf->valuestring);
		if (l < 0) {
			hlog(LOG_ERR, "Live upgrade: %s/%s: Failed to decode ibuf: %s", c->addr_rem, c->username, ibuf->valuestring);
		} else {
			c->ibuf_end = l;
			hlog(LOG_DEBUG, "Live upgrade: Decoded ibuf %d bytes: '%.*s'", l, l, c->ibuf);
			hlog(LOG_DEBUG, "Hex: %s", ibuf->valuestring);
		}
	}
	
	// fill up obuf
	if (obuf && obuf->type == cJSON_String && obuf->valuestring) {
		int l = hex_decode(c->obuf, c->obuf_size, obuf->valuestring);
		if (l < 0) {
			hlog(LOG_ERR, "Live upgrade: %s/%s: Failed to decode obuf: %s", c->addr_rem, c->username, obuf->valuestring);
		} else {
			c->obuf_start = 0;
			c->obuf_end = l;
			hlog(LOG_DEBUG, "Live upgrade: Decoded obuf %d bytes: '%.*s'", l, l, c->obuf);
			hlog(LOG_DEBUG, "Hex: %s", obuf->valuestring);
		}
	}
	
	/* load list of stations heard by this client, to immediately support
	 * messaging
	 */
	if (client_heard && client_heard->type == cJSON_Array)
		client_heard_json_load(c, client_heard);
	
	/* load rxerrs counters, with error name string mapping to support
	 * adding/reordering of error counters
	 */
	if (rx_errs && rx_errs->type == cJSON_Array && rxerr_map && rxerr_map_len > 0)
		accept_rx_err_load(c, rx_errs, rxerr_map, rxerr_map_len);
	
	/* set client lat/lon, if they're given
	 */
	if (lat && lng && lat->type == cJSON_Number && lng->type == cJSON_Number) {
		c->loc_known = 1;
		c->lat = lat->valuedouble;
		c->lng = lng->valuedouble;
	}
	
	hlog(LOG_DEBUG, "%s - Accepted live upgrade client on fd %d from %s", c->addr_loc, c->fd, c->addr_rem);
	
	/* set client socket options, return -1 on serious errors */
	if (set_client_sockopt(c) != 0)
		goto err;
	
	/* Add the client to the client list. */
	int old_fd = clientlist_add(c);
	if (c->validated && old_fd != -1) {
		/* TODO: If old connection is SSL validated, and this one is not, do not disconnect it. */
		hlog(LOG_INFO, "fd %d: Disconnecting duplicate validated client with username '%s'", old_fd, c->username);
		shutdown(old_fd, SHUT_RDWR);
	}
	
	/* ok, found it... lock the new client queue and pass the client */
	if (pass_client_to_worker(pick_next_worker(), c))
		goto err;
	
	return 0;
	
err:
	close(c->fd);
	inbound_connects_account(0, c->portaccount); /* something failed, remove this from accounts.. */
	client_free(c);
	return -1;
}