Пример #1
0
int camd_tcp_connect(struct in_addr ip, int port) {
	ts_LOGf("CAM | Connecting to server %s:%d\n", inet_ntoa(ip), port);

	int fd = socket(PF_INET, SOCK_STREAM, 0);
	if (fd < 0)	{
		ts_LOGf("CAM | Could not create socket | %s\n", strerror(errno));
		return -1;
	}

	struct sockaddr_in sock;
	sock.sin_family = AF_INET;
	sock.sin_port = htons(port);
	sock.sin_addr = ip;
	if (do_connect(fd, (struct sockaddr *)&sock, sizeof(sock), 1000) < 0) {
		ts_LOGf("CAM | Could not connect to server %s:%d | %s\n", inet_ntoa(ip), port, strerror(errno));
		close(fd);
		sleep(1);
		return -1;
	}

	int flag = 1;
	setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));

	ts_LOGf("CAM | Connected to fd:%d\n", fd);
	return fd;
}
Пример #2
0
int udp_connect_input(struct io *io) {
	struct sockaddr_storage addr;
	int addrlen = sizeof(addr);
	int sock = -1;

	memset(&addr, 0, sizeof(addr));

	ts_LOGf("Connecting input to %s port %s\n", io->hostname, io->service);
	if (bind_addr(io->hostname, io->service, SOCK_DGRAM, &addr, &addrlen, &sock) < 0)
		return -1;

	/* Set receive buffer size to ~2.0MB */
	int bufsize = (2000000 / 1316) * 1316;
	setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&bufsize, sizeof(bufsize));

	if (is_multicast(&addr)) {
		if (join_multicast_group(sock, io->ttl, &addr) < 0) {
			close(sock);
			return -1;
		}
	}

	io->fd = sock;
	ts_LOGf("Input connected to fd:%d\n", io->fd);

	return 1;
}
Пример #3
0
static int join_multicast_group(int sock, int ttl, struct sockaddr_storage *addr) {
	switch (addr->ss_family) {
	case AF_INET: {
		struct ip_mreq mreq;
		mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
		mreq.imr_interface.s_addr = INADDR_ANY;

		if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
			ts_LOGf("ERROR: setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
			return -1;
		}
		if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
			ts_LOGf("ERROR: setsockopt(IP_MULTICAST_TTL %d): %s\n", ttl, strerror(errno));
		}
		break;
	}

	case AF_INET6: {
		struct ipv6_mreq mreq6;
		memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
		mreq6.ipv6mr_interface = 0; // interface index, will be set later

		if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
			ts_LOGf("ERROR: setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno));
			return -1;
		}
		if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
			ts_LOGf("ERROR: setsockopt(IPV6_MULTICAST_HOPS %d): %s\n", ttl, strerror(errno));
		}
		break;
	}
	}

	return 0;
}
Пример #4
0
void ts_nit_dump(struct ts_nit *nit) {
	struct ts_section_header *sec = nit->section_header;
	int i;

	ts_section_dump(sec);

	ts_LOGf("  * NIT data\n");
	ts_LOGf("    * PID         : 0x%04x (%d)\n", nit->ts_header.pid, nit->ts_header.pid);
	ts_LOGf("    * reserved1   : 0x%02x\n", nit->reserved1);
	ts_LOGf("    * network_len : 0x%02x (%d)\n", nit->network_info_size, nit->network_info_size);
	ts_LOGf("    * reserved2   : 0x%02x\n", nit->reserved1);
	ts_LOGf("    * ts_loop_len : %d\n", nit->ts_loop_size);
	ts_LOGf("    * num_streams : %d\n", nit->streams_num);

	if (nit->network_info_size > 0) {
		ts_LOGf("  * Network info:\n");
		ts_LOGf("      * network info size: %d\n", nit->network_info_size);
		ts_descriptor_dump(nit->network_info, nit->network_info_size);
	}

	for(i=0;i<nit->streams_num;i++) {
		struct ts_nit_stream *stream = nit->streams[i];
		ts_LOGf("    - [%02d/%02d] | TS_id: 0x%04x (%d) ORG_net_id: 0x%04x (%d) Reserved: 0x%0x Desc_size: %d\n",
			i+1, nit->streams_num,
			stream->transport_stream_id, stream->transport_stream_id,
			stream->original_network_id, stream->original_network_id,
			stream->reserved1,
			stream->descriptor_size);
		if (stream->descriptor_data) {
			ts_descriptor_dump(stream->descriptor_data, stream->descriptor_size);
		}
	}

	ts_nit_check_generator(nit);
}
Пример #5
0
static int camd_send_ecm(struct ts *ts, struct camd_msg *msg) {
	struct camd *c = &ts->camd;
	int ret = c->ops.do_ecm(c, msg);
	if (ret <= 0) {
		ts_LOGf("ERR | Error sending ecm packet, reconnecting to camd.\n");
		ts->is_cw_error = 1;
		c->ops.reconnect(c);
		return ret;
	}

	ret = camd_recv_cw(ts);
	if (ret < 1) {
		time_t now = time(NULL);
		ts->is_cw_error = 1;
		if (ts->key.ts && now - ts->key.ts > KEY_VALID_TIME) {
			if (c->key->is_valid_cw) {
				notify(ts, "NO_CODE_WORD", "No code word was set in %ld sec. Decryption is disabled.",
					now - ts->key.ts);
				ts_LOGf("CW  | *ERR* No valid code word was received in %ld seconds. Decryption is disabled.\n",
					now - ts->key.ts);
				ts->cw_last_warn = time(NULL);
				ts->cw_next_warn = ts->cw_last_warn + ts->cw_warn_sec;
				ts->cw_next_warn -= now - ts->key.ts;
				if (ts->cw_next_warn <= ts->cw_last_warn)
					ts->cw_next_warn = ts->cw_last_warn + ts->cw_warn_sec;
			}
			c->key->is_valid_cw = 0;
		}
		return 0;
	}

	return ret;
}
Пример #6
0
static int camd_recv_cw(struct ts *ts) {
	struct camd *c = &ts->camd;
	struct timeval tv1, tv2, last_ts_keyset;
	uint16_t ca_id = 0;
	uint16_t idx = 0;
	int ret;

	gettimeofday(&tv1, NULL);
	ret = c->ops.get_cw(c, &ca_id, &idx, c->key->cw);
	gettimeofday(&tv2, NULL);

	if (ret <= 0) {
		if (ret == -1) { // Fatal error it is better to reconnect to server.
			ts_LOGf("ERR | No code word has been received (ret = %d)\n", ret);
			c->ops.reconnect(c);
		}
		c->ecm_recv_errors++;
		if (c->ecm_recv_errors >= ECM_RECV_ERRORS_LIMIT) {
			c->key->is_valid_cw = 0;
			memset(c->key->cw, 0, 16); // Invalid CW
		}
		usleep(10000);
		return 0;
	}

	char cw_dump[16 * 6];
	ts_hex_dump_buf(cw_dump, 16 * 6, c->key->cw, 16, 0);

	int valid_cw = memcmp(c->key->cw, invalid_cw, 16) != 0;
	if (!c->key->is_valid_cw && valid_cw) {
		ts_LOGf("CW  | OK: Valid code word was received.\n");
		notify(ts, "CODE_WORD_OK", "Valid code word was received.");
	}
	c->key->is_valid_cw = valid_cw;

	// At first ts_keyset is not initialized
	last_ts_keyset = c->key->ts_keyset;
	if (c->key->is_valid_cw)
		camd_set_cw(ts, c->key->cw, 1);

	if (ts->ecm_cw_log) {
		ts_LOGf("CW  | SID 0x%04x CAID: 0x%04x CW_recv: %5llu ms LastKey: %5llu ms Data: %s\n",
			ts->service_id,
			ca_id,
			timeval_diff_msec(&tv1, &tv2),
			timeval_diff_msec(&last_ts_keyset, &tv2),
			cw_dump );
	}

	return 1;
}
Пример #7
0
int udp_connect_input(struct io *io) {
	struct sockaddr_storage addr;
	int addrlen = sizeof(addr);
	int sock = -1;

	memset(&addr, 0, sizeof(addr));

	if (!io->isrc.s_addr)
		ts_LOGf("Connecting input to %s port %s\n", io->hostname, io->service);
	else
		ts_LOGf("Connecting input to %s port %s source %s\n", io->hostname, io->service, inet_ntoa(io->isrc));

	if (get_input_socket(io->hostname, io->service, SOCK_DGRAM, &addr, &addrlen, &sock) < 0)
		return -1;

	/* Set receive buffer size to ~2.0MB */
	int bufsize = (2000000 / 1316) * 1316;
	setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&bufsize, sizeof(bufsize));

	if (is_multicast(&addr)) {
		if (join_multicast_group(sock, io->ttl, &addr) < 0) {
			close(sock);
			return -1;
		} else {
#ifdef IP_ADD_SOURCE_MEMBERSHIP
			if (io->isrc.s_addr && addr.ss_family == AF_INET) {
				/* Source-specific multicast */
				struct sockaddr_in *src = (struct sockaddr_in *)&addr;
				struct ip_mreq_source imr;
				memset(&imr, 0, sizeof(imr));
				imr.imr_multiaddr = src->sin_addr;
				imr.imr_sourceaddr = io->isrc;
				if (setsockopt(sock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
				    (char *)&imr, sizeof(struct ip_mreq_source)) < 0)
				{
					char str_addr[INET6_ADDRSTRLEN];
					my_inet_ntop(addr.ss_family, (struct sockaddr *)&addr, str_addr, sizeof(str_addr));
					ts_LOGf("ERROR: Can't set multicast group %s source %s: %s\n",
						str_addr, inet_ntoa(io->isrc), strerror(errno));
				}
			}
#endif
		}
	}

	io->fd = sock;
	ts_LOGf("Input connected to fd:%d\n", io->fd);

	return 1;
}
Пример #8
0
static void *camd_thread(void *in_ts) {
	struct ts *ts = in_ts;

	set_thread_name("tsdec-camd");

	while (1) {
		struct camd_msg *msg;
		void *req = queue_get(ts->camd.req_queue); // Waits...
		if (ts->camd_stop)
			break;
		if (!req)
			continue;
		msg = queue_get_nowait(ts->camd.ecm_queue);
		if (!msg)
			msg = queue_get_nowait(ts->camd.emm_queue);
		if (!msg)
			continue;
		camd_do_msg(msg);

		if (ts->camd.ecm_queue->items >= ECM_QUEUE_HARD_LIMIT) {
			ts_LOGf("WRN | Too much items (%d) in ECM queue, dropping the oldest.\n", ts->camd.ecm_queue->items);
			while(ts->camd.ecm_queue->items >= ECM_QUEUE_SOFT_LIMIT) {
				msg = queue_get_nowait(ts->camd.ecm_queue);
				camd_msg_free(&msg);
			}
		}

		if (ts->camd.emm_queue->items >= EMM_QUEUE_HARD_LIMIT) {
			ts_LOGf("WRN | Too much items (%d) in EMM queue, dropping the oldest.%s\n",
				ts->camd.emm_queue->items, ts->camd.ops.proto == CAMD_NEWCAMD ?
				" Consider switching to cs378x protocol!" : "");
			while(ts->camd.emm_queue->items >= EMM_QUEUE_SOFT_LIMIT) {
				msg = queue_get_nowait(ts->camd.emm_queue);
				camd_msg_free(&msg);
			}
		}
	}
	// Flush ECM queue
	while (ts->camd.ecm_queue->items) {
		struct camd_msg *msg = queue_get_nowait(ts->camd.ecm_queue);
		camd_msg_free(&msg);
	}
	// Flush EMM queue
	while (ts->camd.emm_queue->items) {
		struct camd_msg *msg = queue_get_nowait(ts->camd.emm_queue);
		camd_msg_free(&msg);
	}

	pthread_exit(EXIT_SUCCESS);
}
Пример #9
0
int ts_pat_parse(struct ts_pat *pat) {
	uint8_t *section_data = pat->section_header->data;
	int section_len = pat->section_header->data_len;

	while (section_len > 0) {
		if (pat->programs_num == pat->programs_max) {
			ts_LOGf("PAT contains too many programs (>%d), not all are initialized!\n", pat->programs_max);
			break;
		}
		struct ts_pat_program *pinfo = calloc(1, sizeof(struct ts_pat_program));

		pinfo->program  = (section_data[0] << 8) | section_data[1];				// xxxxxxxx xxxxxxxx
		pinfo->reserved = (section_data[2] &~ 0x1F) >> 5;						// xxx11111
		pinfo->pid      = ((section_data[2] &~ 0xE0) << 8) | section_data[3];	// 111xxxxx xxxxxxxx

		pat->programs[pat->programs_num] = pinfo;
		pat->programs_num++;

		section_data += 4;
		section_len  -= 4;
	}

	if (!ts_crc32_section_check(pat->section_header, "PAT"))
		return 0;

	pat->initialized = 1;
	return 1;
}
Пример #10
0
static int get_socket(const char *hostname, const char *service, int socktype, struct sockaddr_storage *addr, int *addrlen, int *sock, bool is_output) {
	struct addrinfo hints, *res, *ressave;
	int n, ret = -1;

	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = ai_family;
	hints.ai_socktype = socktype;

	n = getaddrinfo(hostname, service, &hints, &res);
	if (n < 0) {
		ts_LOGf("ERROR: getaddrinfo(%s): %s\n", hostname, gai_strerror(n));
		return ret;
	}

	ressave = res;
	while (res) {
		*sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
		if (*sock > -1) {
			int on = 1;
			setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
			set_sock_nonblock(*sock);
			if (is_output) {
				memcpy(addr, res->ai_addr, res->ai_addrlen);
				*addrlen = res->ai_addrlen;
				ret = 0;
				break;
			}
			if (bind(*sock, res->ai_addr, res->ai_addrlen) == 0) {
				memcpy(addr, res->ai_addr, res->ai_addrlen);
				*addrlen = res->ai_addrlen;
				ret = 0;
				break;
			} else {
				char str_addr[INET6_ADDRSTRLEN];
				my_inet_ntop(res->ai_family, res->ai_addr, str_addr, sizeof(str_addr));
				ts_LOGf("ERROR: bind: %s:%s (%s): %s\n",
					hostname, service, str_addr, strerror(errno));
			}
			close(*sock);
			*sock = -1;
		}
		res = res->ai_next;
	}
	freeaddrinfo(ressave);

	return ret;
}
Пример #11
0
int ts_nit_parse(struct ts_nit *nit) {
	uint8_t *section_data = nit->section_header->data;
	int section_len = nit->section_header->data_len;

	/* Table data (2 bytes) */
	nit->reserved1         =  (section_data[0] &~ 0x0F) >> 4;						// xxxx1111
	nit->network_info_size = ((section_data[0] &~ 0xF0) << 8) | section_data[1];	// 1111xxxx xxxxxxxx

	/* Handle streams */
	uint8_t *stream_data = section_data + 2 + nit->network_info_size;	// +2 is to compensate for reserved1 and network_info_size
	int stream_len       = section_len - nit->network_info_size - 4;	// -4 for the CRC at the end

	nit->network_info = NULL;
	if (nit->network_info_size) {
		nit->network_info = malloc(nit->network_info_size);
		if (nit->network_info) {
			memcpy(nit->network_info, stream_data - nit->network_info_size, nit->network_info_size);
		}
	}

	// Before the table there are two more fields
	nit->reserved2    =  (stream_data[0] &~ 0x0F) >> 4;						// xxxx1111
	nit->ts_loop_size = ((stream_data[0] &~ 0xF0) << 8) | stream_data[1];	// 1111xxxx xxxxxxxx

	stream_data += 2;
	stream_len   = nit->ts_loop_size;

	while (stream_len > 0) {
		if (nit->streams_num == nit->streams_max) {
			ts_LOGf("!!! Too many streams in NIT, max %d\n", nit->streams_max);
			break;
		}

		struct ts_nit_stream *sinfo = calloc(1, sizeof(struct ts_nit_stream));

		sinfo->transport_stream_id = (stream_data[0] << 8) | stream_data[1];
		sinfo->original_network_id = (stream_data[2] << 8) | stream_data[3];

		sinfo->reserved1           =  (stream_data[4] &~ 0x0F) >> 4;					// xxxx1111
		sinfo->descriptor_size     = ((stream_data[4] &~ 0xF0) << 8) | stream_data[5];	// 1111xxxx xxxxxxxx

		sinfo->descriptor_data      = NULL;
		if (sinfo->descriptor_size > 0) {
			sinfo->descriptor_data = malloc(sinfo->descriptor_size);
			memcpy(sinfo->descriptor_data, &stream_data[6], sinfo->descriptor_size);
		}
		nit->streams[nit->streams_num] = sinfo;
		nit->streams_num++;

		stream_data += 6 + sinfo->descriptor_size;
		stream_len  -= 6 + sinfo->descriptor_size;
	}

	if (!ts_crc32_section_check(nit->section_header, "NIT"))
		return 0;

	nit->initialized = 1;
	return 1;
}
Пример #12
0
static void dvb_print_string(char *pad, char *prefix, uint8_t *input, int text_length) {
	if (text_length < 0) {
		ts_LOGf("%s  !!! %s text_length < 0, %d\n", pad, prefix, text_length);
		return;
	}
	if (text_length == 0) {
		ts_LOGf("%s  %s \"\" (size: %d)\n", pad, prefix, text_length);
		return;
	}
	char *text = calloc(1, text_length + 1);
	memcpy(text, input, text_length);
	if (text[0] < 32)
		ts_LOGf("%s  %s \"%s\" (charset: 0x%02x size: %d)\n", pad, prefix, text+1, text[0], text_length-1);
	else
		ts_LOGf("%s  %s \"%s\" (size: %d)\n", pad, prefix, text, text_length);
	free(text);
}
Пример #13
0
void ts_compare_data(char *prefix, uint8_t *a, uint8_t *b, int size) {
	if (!a) {
		ts_LOGf("%s: !a\n", prefix);
		return;
	}
	if (!b) {
		ts_LOGf("%s: !b\n", prefix);
		return;
	}
	if (memcmp(a, b, size) == 0) {
		ts_LOGf("   **** %s generator is correct ****\n", prefix);
	} else {
		int i;
		for (i=0;i<size;i++) {
			ts_LOGf("%03d - %02x %02x | %s\n", i, a[i], b[i], a[i] == b[i] ? "ok" : "err");
		}
	}
}
Пример #14
0
int ts_pmt_parse(struct ts_pmt *pmt) {
	uint8_t *section_data = pmt->section_header->data;
	int section_len = pmt->section_header->data_len;

	pmt->reserved1         =  (section_data[0] &~ 0x1F) >> 5;						// xxx11111
	pmt->PCR_pid           = ((section_data[0] &~ 0xE0) << 8) | section_data[1];	// 111xxxxx xxxxxxxx

	pmt->reserved2         =  (section_data[2] &~ 0x0F) >> 4;						// xxxx1111
	pmt->program_info_size = ((section_data[2] &~ 0xF0) << 8) | section_data[3];	// 1111xxxx xxxxxxxx

	/* Handle streams */
	uint8_t *stream_data = section_data + 4 + pmt->program_info_size;	// +4 is to compensate for reserved1,PCR,reserved2,program_info_size
	int stream_len       = section_len - pmt->program_info_size - 4;		// -4 for the CRC at the end

	pmt->program_info = NULL;
	if (pmt->program_info_size) {
		pmt->program_info = malloc(pmt->program_info_size);
		if (pmt->program_info) {
			memcpy(pmt->program_info, stream_data - pmt->program_info_size, pmt->program_info_size);
		}
	}

	while (stream_len > 0) {
		if (pmt->streams_num == pmt->streams_max) {
			ts_LOGf("PMT contains too many streams (>%d), not all are initialized!\n", pmt->streams_max);
			break;
		}

		struct ts_pmt_stream *sinfo = calloc(1, sizeof(struct ts_pmt_stream));

		sinfo->stream_type  = stream_data[0];

		sinfo->reserved1    =  (stream_data[1] &~ 0x1F) >> 5;					// xxx11111
		sinfo->pid          = ((stream_data[1] &~ 0xE0) << 8) | stream_data[2];	// 111xxxxx xxxxxxxx

		sinfo->reserved2    =  (stream_data[3] &~ 0x0F) >> 4;					// xxxx1111
		sinfo->ES_info_size = ((stream_data[3] &~ 0xF0) << 8) | stream_data[4];	// 1111xxxx xxxxxxxx

		sinfo->ES_info      = NULL;
		if (sinfo->ES_info_size > 0) {
			sinfo->ES_info = malloc(sinfo->ES_info_size);
			memcpy(sinfo->ES_info, &stream_data[5], sinfo->ES_info_size);
		}
		pmt->streams[pmt->streams_num] = sinfo;
		pmt->streams_num++;

		stream_data += 5 + sinfo->ES_info_size;
		stream_len  -= 5 + sinfo->ES_info_size;
	}

	if (!ts_crc32_section_check(pmt->section_header, "PMT"))
		return 0;

	pmt->initialized = 1;
	return 1;
}
Пример #15
0
static void report_cw_warn(struct ts *ts, time_t now) {
	if (now - ts->key.ts > 1) {
		notify(ts, "NO_CODE_WORD", "No valid code word was received in %ld sec.",
			now - ts->key.ts);
		ts_LOGf("CW  | *ERR* No valid code word was received for %ld seconds!\n",
			now - ts->key.ts);
	}
	ts->cw_last_warn = now;
	ts->cw_next_warn = now + ts->cw_warn_sec;
}
Пример #16
0
static void do_reports(struct ts *ts) {
	static int first_emm_report = 1;
	static int first_ecm_report = 1;
	time_t now = time(NULL);
	if (ts->process_emm && ts->emm_report_interval) {
		if (first_emm_report && now >= ts->emm_last_report) {
			first_emm_report = 0;
			ts->emm_last_report -= FIRST_REPORT_SEC;
			report_emms(ts, now);
		} else if ((time_t)(ts->emm_last_report + ts->emm_report_interval) <= now) {
			report_emms(ts, now);
		}
	}
	if (ts->process_ecm && ts->ecm_report_interval) {
		if (first_ecm_report && now >= ts->ecm_last_report) {
			first_ecm_report = 0;
			ts->ecm_last_report -= FIRST_REPORT_SEC;
			report_ecms(ts, now);
		} else if ((time_t)(ts->ecm_last_report + ts->ecm_report_interval) <= now) {
			report_ecms(ts, now);
		}
	}
	if (ts->stream_is_not_scrambled && ts->last_not_scrambled_report_ts <= now - 60) {
		ts_LOGf("CLR | No encrypted packets in the last %ld seconds. Stream is clear.\n", now - ts->last_scrambled_packet_ts);
		notify(ts, "STREAM_CLEAR", "No encrypted packets in the last %ld seconds. Stream is clear.", now - ts->last_scrambled_packet_ts);
		ts->last_not_scrambled_report_ts = now;
	}
	if (ts->process_ecm && !ts->key.is_valid_cw) {
		if (ts->cw_warn_sec && now >= ts->cw_next_warn) {
			report_cw_warn(ts, now);
		}
	}
	if (!ts->no_input) {
		if (ts->last_pmt_ts <= now - 3) {
			if (ts->have_valid_pmt) {
				ts_LOGf("MIS | There is no valid PMT in the input.\n");
				notify(ts, "NO_PROGRAM", "The input is missing valid program.");
				ts->have_valid_pmt = 0;
			}
		}
	}
}
Пример #17
0
void signal_quit(int sig) {
	if (!keep_running)
		raise(sig);
	keep_running = 0;
	ts_LOGf("Killed %s with signal %d\n", program_id, sig);
	if (ts.input.type == NET_IO)
		shutdown_fd(&ts.input.fd);
	if (ts.output.type == NET_IO)
		shutdown_fd(&ts.output.fd);
	signal(sig, SIG_DFL);
}
Пример #18
0
static void report_ecms(struct ts *ts, time_t now) {
	ts_LOGf("ECM | Received %u (%u dup) and processed %u in %lu seconds.\n",
		ts->ecm_seen_count,
		ts->ecm_duplicate_count,
		ts->ecm_processed_count,
		now - ts->ecm_last_report);
	ts->ecm_last_report = now;
	ts->ecm_seen_count = 0;
	ts->ecm_duplicate_count = 0;
	ts->ecm_processed_count = 0;
}
Пример #19
0
void ts_cat_dump(struct ts_cat *cat) {
	struct ts_section_header *sec = cat->section_header;

	ts_section_dump(sec);

	if (cat->program_info_size > 0) {
		ts_LOGf("  * Descriptor dump:\n");
		ts_descriptor_dump(cat->program_info, cat->program_info_size);
	}

	ts_cat_check_generator(cat);
}
Пример #20
0
static void report_cw_warn(struct ts *ts, time_t now) {
	if (ts->stream_is_not_scrambled || !ts->have_valid_pmt || ts->no_input)
		return;
	if (now - ts->key.ts > 1) {
		notify(ts, "NO_CODE_WORD", "No valid code word was received in %ld sec.",
			now - ts->key.ts);
		ts_LOGf("CW  | *ERR* No valid code word was received for %ld seconds!\n",
			now - ts->key.ts);
	}
	ts->cw_last_warn = now;
	ts->cw_next_warn = now + ts->cw_warn_sec;
}
Пример #21
0
static void report_ecms(struct ts *ts, time_t now) {
	if ((ts->stream_is_not_scrambled || !ts->have_valid_pmt || ts->no_input) && ts->ecm_seen_count == 0)
		return;
	ts_LOGf("ECM | Received %u (%u dup) and processed %u in %lu seconds.\n",
		ts->ecm_seen_count,
		ts->ecm_duplicate_count,
		ts->ecm_processed_count,
		now - ts->ecm_last_report);
	ts->ecm_last_report = now;
	ts->ecm_seen_count = 0;
	ts->ecm_duplicate_count = 0;
	ts->ecm_processed_count = 0;
}
Пример #22
0
void ts_pat_dump(struct ts_pat *pat) {
	struct ts_section_header *sec = pat->section_header;
	int i;

	ts_section_dump(sec);

	ts_LOGf("  * PAT data\n");
	ts_LOGf("    * num_programs: %d\n", pat->programs_num);
	for (i=0;i<pat->programs_num;i++) {
		struct ts_pat_program *prg = pat->programs[i];
		ts_LOGf("      * [%02d/%02d]: Program No 0x%04x (%5d) -> PID %04x (%d) /res: 0x%02x/\n",
			i+1, pat->programs_num,
			prg->program, prg->program,
			prg->pid, prg->pid,
			prg->reserved);
		// Program number 0 is Network ID, not program id
		if (prg->program == 0) {
			ts_LOGf("      - NIT PID %04x (%d)\n", prg->pid, prg->pid);
		}
	}

	ts_pat_check_generator(pat);
}
Пример #23
0
struct ts_pat *ts_pat_copy(struct ts_pat *pat) {
	struct ts_pat *newpat = ts_pat_alloc();
	int i;
	for (i=0;i<pat->section_header->num_packets; i++) {
		newpat = ts_pat_push_packet(newpat, pat->section_header->packet_data + (i * TS_PACKET_SIZE));
	}
	if (newpat->initialized) {
		return newpat;
	} else {
		ts_LOGf("Error copying PAT!\n");
		ts_pat_free(&newpat);
		return NULL;
	}
}
Пример #24
0
static int camd_send_emm(struct ts *ts, struct camd_msg *msg) {
	struct camd *c = &ts->camd;
	int ret = c->ops.do_emm(c, msg);
	if (ret < 1) {
		c->emm_recv_errors++;
		if (c->emm_recv_errors >= EMM_RECV_ERRORS_LIMIT) {
			ts_LOGf("ERR | Error sending emm packet, reconnecting to camd.\n");
			c->ops.reconnect(c);
			c->emm_recv_errors = 0;
		}
	} else {
			c->emm_recv_errors = 0;
	}
	return ret;
}
Пример #25
0
void ts_pmt_dump(struct ts_pmt *pmt) {
	struct ts_section_header *sec = pmt->section_header;
	int i;

	ts_section_dump(sec);

	ts_LOGf("  * PMT data\n");
	ts_LOGf("    * PID         : %04x (%d)\n", pmt->ts_header.pid, pmt->ts_header.pid);
	ts_LOGf("    * reserved1   : %d\n", pmt->reserved1);
	ts_LOGf("    * PCR PID     : %04x (%d)\n", pmt->PCR_pid, pmt->PCR_pid);
	ts_LOGf("    * reserved2   : %d\n", pmt->reserved2);
	ts_LOGf("    * program_len : %d\n", pmt->program_info_size);
	ts_LOGf("    * num_streams : %d\n", pmt->streams_num);

	if (pmt->program_info_size > 0) {
		ts_LOGf("  * Program info:\n");
		ts_LOGf("      * program info size: %d\n", pmt->program_info_size);
		ts_descriptor_dump(pmt->program_info, pmt->program_info_size);
	}

	for(i=0;i<pmt->streams_num;i++) {
		struct ts_pmt_stream *stream = pmt->streams[i];
		ts_LOGf("    * [%02d/%02d] PID %04x (%d) -> Stream type: 0x%02x (%d) /es_info_size: %d/ %s\n",
			i+1, pmt->streams_num,
			stream->pid, stream->pid,
			stream->stream_type, stream->stream_type,
			stream->ES_info_size,
			h222_stream_type_desc(stream->stream_type)
		);
		if (stream->ES_info) {
			ts_descriptor_dump(stream->ES_info, stream->ES_info_size);
		}
	}

	ts_pmt_check_generator(pmt);
}
Пример #26
0
int udp_connect_output(struct io *io) {
	struct sockaddr_storage addr;
	int addrlen = sizeof(addr);
	int sock = -1;

	memset(&addr, 0, sizeof(addr));

	ts_LOGf("Connecting output to %s port %s ttl: %d\n",
		io->hostname, io->service, io->ttl);
	if (bind_addr(io->hostname, io->service, SOCK_DGRAM, &addr, &addrlen, &sock) < 0)
		return -1;

	/* Set send buffer size to ~2.0MB */
	int bufsize = (2000000 / 1316) * 1316;
	setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&bufsize, sizeof(bufsize));

	if (is_multicast(&addr)) {
		if (join_multicast_group(sock, io->ttl, &addr) < 0) {
			close(sock);
			return -1;
		} else {
			if (addr.ss_family == AF_INET) {
				if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &io->intf, sizeof(io->intf)) < 0) {
					ts_LOGf("ERROR: setsockopt(IP_MUTICAST_IF %s): %s\n", inet_ntoa(io->intf), strerror(errno));
					close(sock);
					return -1;
				}
			}
			if (addr.ss_family == AF_INET6 && io->v6_if_index > -1) {
				if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (void *)&io->v6_if_index, sizeof(io->v6_if_index)) < 0) {
					ts_LOGf("ERROR: setsockopt(IPV6_MUTICAST_IF %d): %s\n", io->v6_if_index, strerror(errno));
					close(sock);
					return -1;
				}
			}
		}
	}

	if (addr.ss_family == AF_INET && io->tos > -1) {
		if (setsockopt(sock, IPPROTO_IP, IP_TOS, &io->tos, sizeof(io->tos)) < 0) {
			ts_LOGf("ERROR: setsockopt(IP_TOS 0x%02x): %s\n", io->tos, strerror(errno));
		}
	}

	if (connect(sock, (struct sockaddr *)&addr, addrlen) < 0) {
		ts_LOGf("ERROR: udp_connect(): %s\n", strerror(errno));
		close(sock);
		return -1;
	}
	io->fd = sock;
	ts_LOGf("Output connected to fd:%d\n", io->fd);

	return 1;
}
Пример #27
0
static void report_emms(struct ts *ts, time_t now) {
	ts_LOGf("EMM | Received %u, Skipped %u, Sent %u, Processed %u in %lu seconds.\n",
		ts->emm_input_count,
		ts->emm_skipped_count,
		ts->emm_seen_count,
		ts->emm_processed_count,
		now - ts->emm_last_report);
	if (ts->emm_seen_count == 0) {
		notify(ts, "NO_EMM_RECEIVED", "No EMMs were received in last %lu seconds.",
			now - ts->emm_last_report);
	}
	ts->emm_last_report = now;
	ts->emm_input_count = 0;
	ts->emm_seen_count = 0;
	ts->emm_skipped_count = 0;
	ts->emm_processed_count = 0;
}
Пример #28
0
void ts_pat_check_generator(struct ts_pat *pat) {
	struct ts_pat *pat1 = ts_pat_copy(pat);
	if (pat1) {
		ts_compare_data("PAT (tspacket->struct)",
			pat1->section_header->packet_data,
			pat->section_header->packet_data,
			pat->section_header->num_packets * TS_PACKET_SIZE);
		ts_pat_free(&pat1);
	}

	uint8_t *ts_packets;
	int num_packets;
	ts_pat_generate(pat, &ts_packets, &num_packets);
	if (num_packets != pat->section_header->num_packets) {
		ts_LOGf("ERROR: num_packets:%d != sec->num_packets:%d\n", num_packets, pat->section_header->num_packets);
	}
	ts_compare_data("PAT (struct->tspacket)", pat->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
	free(ts_packets);
}
Пример #29
0
void ts_nit_check_generator(struct ts_nit *nit) {
	struct ts_nit *nit1 = ts_nit_alloc();
	int i;
	for (i=0;i<nit->section_header->num_packets;i++) {
		nit1 = ts_nit_push_packet(nit1, nit->section_header->packet_data + (i * TS_PACKET_SIZE));
	}
	ts_compare_data("NIT (tspacket->struct)",
		nit1->section_header->packet_data,
		nit->section_header->packet_data,
		nit->section_header->num_packets * TS_PACKET_SIZE);
	ts_nit_free(&nit1);

	uint8_t *ts_packets;
	int num_packets;
	ts_nit_generate(nit, &ts_packets, &num_packets);
	if (num_packets != nit->section_header->num_packets) {
		ts_LOGf("ERROR: num_packets:%d != sec->num_packets:%d\n", num_packets, nit->section_header->num_packets);
	}
	ts_compare_data("NIT (struct->tspacket)", nit->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
	free(ts_packets);
}
Пример #30
0
void ts_descriptor_dump(uint8_t *desc_data, int desc_data_len) {
	char *pad  = "        * ";
	uint8_t *data = desc_data;
	int data_len = desc_data_len;
	while (data_len >= 2) {
		int i;
		uint8_t tag         = data[0];
		uint8_t this_length = data[1];

//		ts_LOGf("%sDescriptor tag: 0x%02x (%d) size: %d\n", padA, tag, tag, this_length);

		data     += 2;
		data_len -= 2;

		if (this_length > data_len) {
			// Not much we can do - try giving up?
			ts_LOGf("%s!!! Descriptor 0x%02x says length %d, but only %d bytes left\n", pad, tag, this_length, data_len);
			return;
		}

		switch (tag) {
			case  2: { // Video stream descriptor
				char *dump = ts_hex_dump(data, this_length, 0);
				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Video stream descriptor: %s\n", pad, tag, tag, this_length, dump);
				free(dump);
				struct {
					uint8_t multiple_frame_rate_flag     : 1,
					        frame_rate_code              : 4,
					        mpeg1_only_flag              : 1,
					        constraint_parameter_flag    : 1,
					        still_picture_flag           : 1;
					uint8_t profile_and_level_indication;
					uint8_t chroma_format                : 2,
					        frame_rate_extension_flag    : 1,
					        reserved                     : 5;
					uint8_t escape:1, profile:3, level:4;
				} vs;
				if (this_length >= 1) {
					vs.multiple_frame_rate_flag     = bit_on(data[0], bit_8);
					vs.frame_rate_code              = (data[0] &~ 0x80) >> 3; // 1xxxx111
					vs.mpeg1_only_flag              = bit_on(data[0], bit_3);
					vs.constraint_parameter_flag    = bit_on(data[0], bit_2);
					vs.still_picture_flag           = bit_on(data[0], bit_1);
					ts_LOGf("%s  - multiple_frame_rate_flag     : %d\n", pad, vs.multiple_frame_rate_flag);
					ts_LOGf("%s  - frame_rate_code              : %d (%s)\n", pad, vs.frame_rate_code,
						vs.frame_rate_code == 0 ? "forbidden" :
						vs.frame_rate_code == 1 ? "23.976" :
						vs.frame_rate_code == 2 ? "24.00" :
						vs.frame_rate_code == 3 ? "25.00" :
						vs.frame_rate_code == 4 ? "29.97" :
						vs.frame_rate_code == 5 ? "30.00" :
						vs.frame_rate_code == 6 ? "50.00" :
						vs.frame_rate_code == 7 ? "59.94" :
						vs.frame_rate_code == 8 ? "60.00" : "reserved"
					);
					ts_LOGf("%s  - mpeg1_only_flag              : %d\n", pad, vs.mpeg1_only_flag);
					ts_LOGf("%s  - constraint_parameter_flag    : %d\n", pad, vs.constraint_parameter_flag);
					ts_LOGf("%s  - still_picture_flag           : %d\n", pad, vs.still_picture_flag);
				}
				if (this_length >= 2 && vs.mpeg1_only_flag == 0) {
					vs.profile_and_level_indication = data[1];
					vs.chroma_format                = data[2] >> 6;				// xx111111
					vs.frame_rate_extension_flag    = bit_on(data[2], bit_6);	// 11x11111
					vs.reserved                     = data[2] &~ 0xE0;			// 111xxxxx
					vs.profile                      = (vs.profile_and_level_indication &~ 0x8f) >> 4;	// x111xxxx
					vs.level                        =  vs.profile_and_level_indication &~ 0xf0;			// xxxx1111
					ts_LOGf("%s  - profile_and_level_indication : 0x%02x, Profile: %d (%s), Level: %d (%s)\n", pad,
						vs.profile_and_level_indication,

						vs.profile,
						vs.profile == 1 ? "High"               :
						vs.profile == 2 ? "Spatially Scalable" :
						vs.profile == 3 ? "SNR Scalable"       :
						vs.profile == 4 ? "Main"               :
						vs.profile == 5 ? "Simple"             : "Reserved",

						vs.level,
						vs.level == 4  ? "High"      :
						vs.level == 6  ? "High 1440" :
						vs.level == 8  ? "Main"      :
						vs.level == 10 ? "Low"       : "Reserved"
					);
					ts_LOGf("%s  - chroma_format                : %d (%s)\n", pad, vs.chroma_format,
						vs.chroma_format == 0 ? "reserved" :
						vs.chroma_format == 1 ? "4:2:0" :
						vs.chroma_format == 2 ? "4:2:2" :
						vs.chroma_format == 3 ? "4:4:4" : "unknown"
					);
					ts_LOGf("%s  - frame_rate_extension_flag    : %d\n", pad, vs.frame_rate_extension_flag);
					ts_LOGf("%s  - reserved                     : 0x%x\n", pad, vs.reserved);
				}
				break;
			}
			case  3: { // Audio stream descriptor
				char *dump = ts_hex_dump(data, this_length, 0);
				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Audio stream descriptor: %s\n", pad, tag, tag, this_length, dump);
				free(dump);
				struct {
					uint8_t free_format_flag : 1,
					        ID               : 1,
					        layer            : 2,
					        vbr_flag         : 1,
					        reserved         : 3;
				} as;
				if (this_length >= 1) {
					as.free_format_flag = bit_on(data[0], bit_8);
					as.ID               = bit_on(data[0], bit_7);
					as.layer            = (data[0] &~ 0xcf) >> 4;	// 11xx1111
					as.vbr_flag         = bit_on(data[0], bit_4);
					as.reserved         = data[0] &~ 0xf0;			// 1111xxxx
					ts_LOGf("%s  - free_format_flag : %d\n", pad, as.free_format_flag);
					ts_LOGf("%s  - ID               : %d (%s)\n", pad, as.ID, as.ID ? "MPEG Audio" : "Other");
					ts_LOGf("%s  - layer            : %d (%s)\n", pad, as.layer,
						as.layer == 0 ? "reserved" :
						as.layer == 1 ? "Layer III" :
						as.layer == 2 ? "Layer II" :
						as.layer == 3 ? "Layer I" : "reserved"
					);
					ts_LOGf("%s  - vbr_audio_flag   : %d\n", pad, as.vbr_flag);
					ts_LOGf("%s  - reserved         : 0x%x\n", pad, as.reserved);
				}
				break;
			}