mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-14 00:04:13 +09:00
fix unsafe strcmp (AirMyPC segfault) + timing fix for AirMyPC client
This commit is contained in:
@@ -70,8 +70,9 @@ struct raop_callbacks_s {
|
||||
void (*video_report_size)(void *cls, float *width_source, float *height_source, float *width, float *height);
|
||||
};
|
||||
typedef struct raop_callbacks_s raop_callbacks_t;
|
||||
raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const unsigned char *remote_addr, int remote_addr_len, unsigned short timing_rport);
|
||||
|
||||
raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const unsigned char *remote_addr, int remote_addr_len,
|
||||
unsigned short timing_rport, timing_protocol_t *time_protocol);
|
||||
|
||||
RAOP_API raop_t *raop_init(int max_clients, raop_callbacks_t *callbacks);
|
||||
RAOP_API void raop_set_log_level(raop_t *raop, int level);
|
||||
RAOP_API void raop_set_log_callback(raop_t *raop, raop_log_callback_t callback, void *cls);
|
||||
|
||||
@@ -445,13 +445,28 @@ raop_handler_setup(raop_conn_t *conn,
|
||||
" Only AirPlay v1 protocol (using NTP and timing port) is supported");
|
||||
}
|
||||
}
|
||||
uint64_t string_len;
|
||||
uint64_t string_len = 0;
|
||||
const char *timing_protocol;
|
||||
timing_protocol_t time_protocol;
|
||||
plist_t req_timing_protocol_node = plist_dict_get_item(req_root_node, "timingProtocol");
|
||||
timing_protocol = plist_get_string_ptr(req_timing_protocol_node, &string_len);
|
||||
if (strcmp(timing_protocol, "NTP")) {
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "Client specified timingProtocol=%s, but timingProtocol= NTP is required here", timing_protocol);
|
||||
}
|
||||
if (string_len) {
|
||||
if (strncmp(timing_protocol, "NTP", string_len) == 0) {
|
||||
time_protocol = NTP;
|
||||
} else if (strncmp(timing_protocol, "None", string_len) == 0) {
|
||||
time_protocol = TP_NONE;
|
||||
} else {
|
||||
time_protocol = TP_OTHER;
|
||||
}
|
||||
if (time_protocol != NTP) {
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "Client specified timingProtocol=%s,"
|
||||
" but timingProtocol= NTP is required here", timing_protocol);
|
||||
}
|
||||
} else {
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "Client did not specify timingProtocol,"
|
||||
" old protocol without offset will be used");
|
||||
time_protocol = TP_UNSPECIFIED;
|
||||
}
|
||||
timing_protocol = NULL;
|
||||
uint64_t timing_rport = 0;
|
||||
plist_t req_timing_port_node = plist_dict_get_item(req_root_node, "timingPort");
|
||||
@@ -461,14 +476,18 @@ raop_handler_setup(raop_conn_t *conn,
|
||||
if (timing_rport) {
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "timing_rport = %llu", timing_rport);
|
||||
} else {
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "Client did not supply timing_rport, may be using unsupported AirPlay2 \"Remote Control\" protocol");
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "Client did not supply timing_rport,"
|
||||
" may be using unsupported AirPlay2 \"Remote Control\" protocol");
|
||||
}
|
||||
unsigned short timing_lport = conn->raop->timing_lport;
|
||||
conn->raop_ntp = raop_ntp_init(conn->raop->logger, &conn->raop->callbacks, conn->remote, conn->remotelen, timing_rport);
|
||||
conn->raop_ntp = raop_ntp_init(conn->raop->logger, &conn->raop->callbacks, conn->remote,
|
||||
conn->remotelen, (unsigned short) timing_rport, &time_protocol);
|
||||
raop_ntp_start(conn->raop_ntp, &timing_lport, conn->raop->max_ntp_timeouts);
|
||||
|
||||
conn->raop_rtp = raop_rtp_init(conn->raop->logger, &conn->raop->callbacks, conn->raop_ntp, conn->remote, conn->remotelen, aeskey, aesiv);
|
||||
conn->raop_rtp_mirror = raop_rtp_mirror_init(conn->raop->logger, &conn->raop->callbacks, conn->raop_ntp, conn->remote, conn->remotelen, aeskey);
|
||||
conn->raop_rtp = raop_rtp_init(conn->raop->logger, &conn->raop->callbacks, conn->raop_ntp,
|
||||
conn->remote, conn->remotelen, aeskey, aesiv);
|
||||
conn->raop_rtp_mirror = raop_rtp_mirror_init(conn->raop->logger, &conn->raop->callbacks,
|
||||
conn->raop_ntp, conn->remote, conn->remotelen, aeskey);
|
||||
|
||||
plist_t res_event_port_node = plist_new_uint(conn->raop->port);
|
||||
plist_t res_timing_port_node = plist_new_uint(timing_lport);
|
||||
@@ -498,7 +517,8 @@ raop_handler_setup(raop_conn_t *conn,
|
||||
plist_t stream_id_node = plist_dict_get_item(req_stream_node, "streamConnectionID");
|
||||
uint64_t stream_connection_id;
|
||||
plist_get_uint_val(stream_id_node, &stream_connection_id);
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "streamConnectionID (needed for AES-CTR video decryption key and iv): %llu", stream_connection_id);
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "streamConnectionID (needed for AES-CTR video decryption"
|
||||
" key and iv): %llu", stream_connection_id);
|
||||
|
||||
if (conn->raop_rtp_mirror) {
|
||||
raop_rtp_init_mirror_aes(conn->raop_rtp_mirror, &stream_connection_id);
|
||||
|
||||
@@ -91,6 +91,8 @@ struct raop_ntp_s {
|
||||
|
||||
// UDP socket
|
||||
int tsock;
|
||||
|
||||
timing_protocol_t time_protocol;
|
||||
};
|
||||
|
||||
|
||||
@@ -140,7 +142,7 @@ raop_ntp_parse_remote_address(raop_ntp_t *raop_ntp, const unsigned char *remote_
|
||||
}
|
||||
|
||||
raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const unsigned char *remote_addr,
|
||||
int remote_addr_len, unsigned short timing_rport) {
|
||||
int remote_addr_len, unsigned short timing_rport, timing_protocol_t *time_protocol) {
|
||||
raop_ntp_t *raop_ntp;
|
||||
|
||||
assert(logger);
|
||||
@@ -150,6 +152,7 @@ raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const u
|
||||
if (!raop_ntp) {
|
||||
return NULL;
|
||||
}
|
||||
raop_ntp->time_protocol = *time_protocol;
|
||||
raop_ntp->logger = logger;
|
||||
memcpy(&raop_ntp->callbacks, callbacks, sizeof(raop_callbacks_t));
|
||||
raop_ntp->timing_rport = timing_rport;
|
||||
@@ -322,10 +325,10 @@ raop_ntp_thread(void *arg)
|
||||
int64_t t0 = (int64_t) byteutils_get_ntp_timestamp(response, 8);
|
||||
|
||||
// Local time of the client when the NTP request packet arrives at the client
|
||||
int64_t t1 = (int64_t) byteutils_get_ntp_timestamp(response, 16);
|
||||
int64_t t1 = (int64_t) raop_remote_timestamp_to_nano_seconds(raop_ntp, byteutils_get_long_be(response, 16));
|
||||
|
||||
// Local time of the client when the response message leaves the client
|
||||
int64_t t2 = (int64_t) byteutils_get_ntp_timestamp(response, 24);
|
||||
int64_t t2 = (int64_t) raop_remote_timestamp_to_nano_seconds(raop_ntp, byteutils_get_long_be(response, 24));
|
||||
|
||||
if (logger_debug) {
|
||||
char *str = utils_data_to_string(response, response_len, 16);
|
||||
@@ -480,6 +483,12 @@ uint64_t raop_ntp_timestamp_to_nano_seconds(uint64_t ntp_timestamp, bool account
|
||||
return (seconds * SECOND_IN_NSECS) + ((fraction * SECOND_IN_NSECS) >> 32);
|
||||
}
|
||||
|
||||
uint64_t raop_remote_timestamp_to_nano_seconds(raop_ntp_t *raop_ntp, uint64_t timestamp) {
|
||||
uint64_t seconds = ((timestamp >> 32) & 0xffffffff);
|
||||
if (raop_ntp->time_protocol == NTP) seconds -= SECONDS_FROM_1900_TO_1970;
|
||||
uint64_t fraction = (timestamp & 0xffffffff);
|
||||
return (seconds * SECOND_IN_NSECS) + ((fraction * SECOND_IN_NSECS) >> 32);
|
||||
}
|
||||
/**
|
||||
* Returns the current time in nano seconds according to the local wall clock.
|
||||
* The system Unix time is used as the local wall clock.
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
typedef struct raop_ntp_s raop_ntp_t;
|
||||
|
||||
typedef enum timing_protocol_e { NTP, TP_NONE, TP_OTHER, TP_UNSPECIFIED } timing_protocol_t;
|
||||
|
||||
void raop_ntp_start(raop_ntp_t *raop_ntp, unsigned short *timing_lport, int max_ntp_timeouts);
|
||||
|
||||
@@ -35,6 +36,7 @@ unsigned short raop_ntp_get_port(raop_ntp_t *raop_ntp);
|
||||
void raop_ntp_destroy(raop_ntp_t *raop_rtp);
|
||||
|
||||
uint64_t raop_ntp_timestamp_to_nano_seconds(uint64_t ntp_timestamp, bool account_for_epoch_diff);
|
||||
uint64_t raop_remote_timestamp_to_nano_seconds(raop_ntp_t *raop_ntp, uint64_t timestamp);
|
||||
|
||||
uint64_t raop_ntp_get_local_time(raop_ntp_t *raop_ntp);
|
||||
uint64_t raop_ntp_get_remote_time(raop_ntp_t *raop_ntp);
|
||||
|
||||
@@ -557,7 +557,7 @@ raop_rtp_thread_udp(void *arg)
|
||||
have_synced = true;
|
||||
}
|
||||
uint64_t sync_ntp_raw = byteutils_get_long_be(packet, 8);
|
||||
uint64_t sync_ntp_remote = raop_ntp_timestamp_to_nano_seconds(sync_ntp_raw, true);
|
||||
uint64_t sync_ntp_remote = raop_remote_timestamp_to_nano_seconds(raop_rtp->ntp, sync_ntp_raw);
|
||||
if (logger_debug) {
|
||||
uint64_t sync_ntp_local = raop_ntp_convert_remote_time(raop_rtp->ntp, sync_ntp_remote);
|
||||
char *str = utils_data_to_string(packet, packetlen, 20);
|
||||
|
||||
@@ -321,11 +321,13 @@ raop_rtp_mirror_thread(void *arg)
|
||||
/* packet[4] + packet[5] identify the payload type: values seen are: *
|
||||
* 0x00 0x00: encrypted packet containing a non-IDR type 1 VCL NAL unit *
|
||||
* 0x00 0x10: encrypted packet containing an IDR type 5 VCL NAL unit *
|
||||
* 0x01 0x00 unencrypted packet containing a type 7 SPS NAL + a type 8 PPS NAL unit *
|
||||
* 0x01 0x00: unencrypted packet containing a type 7 SPS NAL + a type 8 PPS NAL unit *
|
||||
* 0x02 0x00: unencryted packet (old protocol) no payload, sent once every second *
|
||||
* 0x05 0x00 unencrypted packet with a "streaming report", sent once per second. */
|
||||
|
||||
/* packet[6] + packet[7] may list a payload "option": values seen are: *
|
||||
* 0x00 0x00 : encrypted and "streaming report" packets *
|
||||
* 0x1e 0x00 : old protocol (seen in AirMyPC) no-payload once-per-second packets *
|
||||
* 0x16 0x01 : seen in most unencrypted SPS+PPS packets *
|
||||
* 0x56 0x01 : occasionally seen in unencrypted SPS+PPS packets (why different?) */
|
||||
|
||||
@@ -400,14 +402,20 @@ raop_rtp_mirror_thread(void *arg)
|
||||
* that has not yet been sent. This will trigger prepending it to the current NAL, and the prepend_sps_pps
|
||||
* flag will be set to false after it has been prepended. */
|
||||
|
||||
if (prepend_sps_pps & (ntp_timestamp_raw != ntp_timestamp_nal)) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG,
|
||||
"raop_rtp_mirror: prepended sps_pps timestamp does not match timestamp of "
|
||||
"video payload\n%llu\n%llu , discarding", ntp_timestamp_raw, ntp_timestamp_nal);
|
||||
free (sps_pps);
|
||||
sps_pps = NULL;
|
||||
prepend_sps_pps = false;
|
||||
}
|
||||
|
||||
if (prepend_sps_pps) {
|
||||
assert(sps_pps);
|
||||
payload_out = (unsigned char*) malloc(payload_size + sps_pps_len);
|
||||
payload_decrypted = payload_out + sps_pps_len;
|
||||
if (ntp_timestamp_raw != ntp_timestamp_nal) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING,
|
||||
"raop_rtp_mirror: prepended sps_pps timestamp does not match timestamp of "
|
||||
"video payload\n%llu\n%llu", ntp_timestamp_raw, ntp_timestamp_nal);
|
||||
}
|
||||
memcpy(payload_out, sps_pps, sps_pps_len);
|
||||
free (sps_pps);
|
||||
@@ -441,6 +449,7 @@ raop_rtp_mirror_thread(void *arg)
|
||||
int nalu_type = payload_decrypted[nalu_size] & 0x1f;
|
||||
int ref_idc = (payload_decrypted[nalu_size] >> 5);
|
||||
switch (nalu_type) {
|
||||
case 14: /* Prefix NALu , seen before all VCL Nalu's in AirMyPc */
|
||||
case 5: /*IDR, slice_layer_without_partitioning */
|
||||
case 1: /*non-IDR, slice_layer_without_partitioning */
|
||||
break;
|
||||
@@ -461,6 +470,24 @@ raop_rtp_mirror_thread(void *arg)
|
||||
free(str);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (logger_debug) {
|
||||
char *str = utils_data_to_string(payload_decrypted + nalu_size, nc_len, 16);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror SPS NAL size = %d", nc_len);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG,
|
||||
"raop_rtp_mirror h264 Sequence Parameter Set:\n%s", str);
|
||||
free(str);
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (logger_debug) {
|
||||
char *str = utils_data_to_string(payload_decrypted + nalu_size, nc_len, 16);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror PPS NAL size = %d", nc_len);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG,
|
||||
"raop_rtp_mirror h264 Picture Parameter Set :\n%s", str);
|
||||
free(str);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_INFO,
|
||||
"unexpected non-VCL NAL unit: nalu_type = %d, ref_idc = %d, nalu_size = %d,"
|
||||
@@ -580,6 +607,10 @@ raop_rtp_mirror_thread(void *arg)
|
||||
// memcpy(h264.picture_parameter_set, picture_parameter_set, pps_size);
|
||||
|
||||
break;
|
||||
case 0x02:
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "\nReceived old-protocol once-per-second packet from client:"
|
||||
" payload_size %d header %s ts_raw = %llu", payload_size, packet_description, ntp_timestamp_raw);
|
||||
/* "old protocol" (used by AirMyPC), rest of 128-byte packet is empty */
|
||||
case 0x05:
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "\nReceived video streaming performance info packet from client:"
|
||||
" payload_size %d header %s ts_raw = %llu", payload_size, packet_description, ntp_timestamp_raw);
|
||||
@@ -615,7 +646,7 @@ raop_rtp_mirror_thread(void *arg)
|
||||
break;
|
||||
default:
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "\nReceived unexpected TCP packet from client, "
|
||||
"size %d, %s ts_raw = raw%llu", payload_size, packet_description, ntp_timestamp_raw);
|
||||
"size %d, %s ts_raw = %llu", payload_size, packet_description, ntp_timestamp_raw);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user