From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Thu, 23 Jun 2022 08:40:30 +0000 (+0100) Subject: Tidy up write encrypted. Explore some of the remote_control connections. Not working. X-Git-Tag: 4.1-rc1~24^2~126 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fb151915ae1e93b1e2b68aa82ff78b72334a4af8;p=thirdparty%2Fshairport-sync.git Tidy up write encrypted. Explore some of the remote_control connections. Not working. --- diff --git a/player.h b/player.h index c4839fad..cda235e3 100644 --- a/player.h +++ b/player.h @@ -310,6 +310,7 @@ typedef struct { timing_t timing_type; // are we using NTP or PTP on this connection? pthread_t *rtp_event_thread; + pthread_t *rtp_data_thread; pthread_t rtp_ap2_control_thread; pthread_t rtp_realtime_audio_thread; pthread_t rtp_buffered_audio_thread; @@ -335,12 +336,14 @@ typedef struct { ap2_pairing ap2_control_pairing; int event_socket; + int data_socket; SOCKADDR ap2_remote_control_socket_addr; // a socket pointing to the control port of the client socklen_t ap2_remote_control_socket_addr_length; int ap2_control_socket; int realtime_audio_socket; int buffered_audio_socket; + uint16_t local_data_port; uint16_t local_event_port; uint16_t local_ap2_control_port; uint16_t local_realtime_audio_port; diff --git a/rtp.c b/rtp.c index 4066b734..c729f286 100644 --- a/rtp.c +++ b/rtp.c @@ -1503,6 +1503,59 @@ int local_ptp_time_to_frame(uint64_t time, uint32_t *frame, rtsp_conn_info *conn return result; } +void rtp_data_receiver_cleanup_handler(void *arg) { + rtsp_conn_info *conn = (rtsp_conn_info *)arg; + debug(2, "Connection %d: AP2 Data Receiver Cleanup.", conn->connection_number); +} + +void *rtp_data_receiver(void *arg) { + rtsp_conn_info *conn = (rtsp_conn_info *)arg; + debug(1, "Connection %d: AP2 Data Receiver started", conn->connection_number); + pthread_cleanup_push(rtp_data_receiver_cleanup_handler, arg); + + listen(conn->data_socket, 5); + + uint8_t packet[4096]; + ssize_t nread; + SOCKADDR remote_addr; + memset(&remote_addr, 0, sizeof(remote_addr)); + socklen_t addr_size = sizeof(remote_addr); + + int fd = accept(conn->data_socket, (struct sockaddr *)&remote_addr, &addr_size); + debug(1, + "Connection %d: rtp_data_receiver accepted a connection on socket %d and moved to a new " + "socket %d.", + conn->connection_number, conn->data_socket, fd); + intptr_t pfd = fd; + pthread_cleanup_push(socket_cleanup, (void *)pfd); + int finished = 0; + do { + nread = recv(fd, packet, sizeof(packet), 0); + + if (nread < 0) { + char errorstring[1024]; + strerror_r(errno, (char *)errorstring, sizeof(errorstring)); + debug(1, "Connection %d: error in ap2 rtp_data_receiver %d: \"%s\". Could not recv a packet.", + conn->connection_number, errno, errorstring); + // if ((config.diagnostic_drop_packet_fraction == 0.0) || + // (drand48() > config.diagnostic_drop_packet_fraction)) { + } else if (nread > 0) { + + // ssize_t plen = nread; + debug(1, "Connection %d: Packet Received on Data Port.", conn->connection_number); + // } else { + // debug(3, "Event Receiver Thread -- dropping incoming packet to simulate a bad network."); + // } + } else { + finished = 1; + } + } while (finished == 0); + pthread_cleanup_pop(1); // close the socket + pthread_cleanup_pop(1); // do the cleanup + debug(2, "Connection %d: AP2 Data Receiver RTP thread \"normal\" exit.", conn->connection_number); + pthread_exit(NULL); +} + void rtp_event_receiver_cleanup_handler(void *arg) { rtsp_conn_info *conn = (rtsp_conn_info *)arg; debug(2, "Connection %d: AP2 Event Receiver Cleanup.", conn->connection_number); @@ -1510,7 +1563,7 @@ void rtp_event_receiver_cleanup_handler(void *arg) { void *rtp_event_receiver(void *arg) { rtsp_conn_info *conn = (rtsp_conn_info *)arg; - debug(2, "Connection %d: AP2 Event Receiver started", conn->connection_number); + debug(1, "Connection %d: AP2 Event Receiver started", conn->connection_number); pthread_cleanup_push(rtp_event_receiver_cleanup_handler, arg); listen(conn->event_socket, 5); @@ -1522,6 +1575,10 @@ void *rtp_event_receiver(void *arg) { socklen_t addr_size = sizeof(remote_addr); int fd = accept(conn->event_socket, (struct sockaddr *)&remote_addr, &addr_size); + debug(2, + "Connection %d: rtp_event_receiver accepted a connection on socket %d and moved to a new " + "socket %d.", + conn->connection_number, conn->event_socket, fd); intptr_t pfd = fd; pthread_cleanup_push(socket_cleanup, (void *)pfd); int finished = 0; @@ -1539,7 +1596,7 @@ void *rtp_event_receiver(void *arg) { } else if (nread > 0) { // ssize_t plen = nread; - debug(1, "Packet Received on Event Port."); + debug(1, "Connection %d: Packet Received on Event Port.", conn->connection_number); if (packet[1] == 0xD7) { debug(1, "Connection %d: AP2 Event Receiver -- Time Announce RTP packet of type 0x%02X length " diff --git a/rtp.h b/rtp.h index 8eff06bb..825bca72 100644 --- a/rtp.h +++ b/rtp.h @@ -25,6 +25,7 @@ int frame_to_local_time(uint32_t timestamp, uint64_t *time, rtsp_conn_info *conn int local_time_to_frame(uint64_t time, uint32_t *frame, rtsp_conn_info *conn); #ifdef CONFIG_AIRPLAY_2 +void *rtp_data_receiver(void *arg); void *rtp_event_receiver(void *arg); void *rtp_ap2_control_receiver(void *arg); void *rtp_realtime_audio_receiver(void *arg); diff --git a/rtsp.c b/rtsp.c index 72cb5ef2..fa5c20ee 100644 --- a/rtsp.c +++ b/rtsp.c @@ -2,7 +2,7 @@ * RTSP protocol handler. This file is part of Shairport Sync * Copyright (c) James Laird 2013 - * Modifications associated with audio synchronization, mutithreading and + * Modifications associated with audio synchronization, multithreading and * metadata handling copyright (c) Mike Brady 2014-2021 * All rights reserved. * @@ -811,10 +811,14 @@ char *msg_get_header(rtsp_message *msg, char *name) { return NULL; } -void debug_print_msg_headers(int level, rtsp_message *msg) { +void _debug_print_msg_headers(const char *filename, const int linenumber, int level, + rtsp_message *msg) { unsigned int i; + if (msg->respcode != 0) + _debug(filename, linenumber, level, " Response Code: %d.", msg->respcode); for (i = 0; i < msg->nheaders; i++) { - debug(level, " Type: \"%s\", content: \"%s\"", msg->name[i], msg->value[i]); + _debug(filename, linenumber, level, " Type: \"%s\", content: \"%s\"", msg->name[i], + msg->value[i]); } } @@ -1046,24 +1050,31 @@ char *rtsp_plist_content(rtsp_message *message) { #endif -void debug_log_rtsp_message(int level, char *prompt, rtsp_message *message) { +void _debug_log_rtsp_message(const char *filename, const int linenumber, int level, char *prompt, + rtsp_message *message) { if (level > debuglev) return; if ((prompt) && (*prompt != '\0')) // okay to pass NULL or an empty list... - debug(level, prompt); - // debug_print_msg_headers(level, message); + _debug(filename, linenumber, level, prompt); + _debug_print_msg_headers(filename, linenumber, level, message); #ifdef CONFIG_AIRPLAY_2 char *plist_content = rtsp_plist_content(message); if (plist_content) { - debug(level, " Content Plist (as XML):\n--\n%s--", plist_content); + _debug(filename, linenumber, level, " Content Plist (as XML):\n--\n%s--", plist_content); free(plist_content); } else #endif { - debug(level, " No Content Plist. Content length: %d.", message->contentlength); + _debug(filename, linenumber, level, " No Content Plist. Content length: %d.", + message->contentlength); } } +#define debug_log_rtsp_message(level, prompt, message) \ + _debug_log_rtsp_message(__FILE__, __LINE__, level, prompt, message) +#define debug_print_msg_headers(level, message) \ + _debug_print_msg_headers(__FILE__, __LINE__, level, message) + #ifdef CONFIG_AIRPLAY_2 static void buf_add(ap2_buffer *buf, uint8_t *in, size_t in_len) { if (buf->len + in_len > buf->size) { @@ -1130,6 +1141,30 @@ static ssize_t read_encrypted(int fd, ap2_pairing *ctx, void *buf, size_t count) return buf_remove(&ctx->plain_buf, buf, count); } +static ssize_t write_encrypted(int fd, ap2_pairing *ctx, const void *buf, size_t count) { + uint8_t *encrypted; + size_t encrypted_len; + + ssize_t ret = pair_encrypt(&encrypted, &encrypted_len, buf, count, ctx->cipher_ctx); + if (ret < 0) { + debug(1, pair_cipher_errmsg(ctx->cipher_ctx)); + return -1; + } + + size_t remain = encrypted_len; + while (remain > 0) { + ssize_t wrote = write(fd, encrypted + (encrypted_len - remain), remain); + if (wrote <= 0) { + free(encrypted); + return wrote; + } + remain -= wrote; + } + free(encrypted); + return count; +} + +/* static ssize_t write_encrypted(rtsp_conn_info *conn, const void *buf, size_t count) { uint8_t *encrypted; size_t encrypted_len; @@ -1153,6 +1188,7 @@ static ssize_t write_encrypted(rtsp_conn_info *conn, const void *buf, size_t cou free(encrypted); return count; } +*/ #endif ssize_t read_from_rtsp_connection(rtsp_conn_info *conn, void *buf, size_t count) { @@ -1417,7 +1453,7 @@ int msg_write_response(rtsp_conn_info *conn, rtsp_message *resp) { #ifdef CONFIG_AIRPLAY_2 ssize_t reply; if (conn->ap2_control_pairing.is_encrypted) { - reply = write_encrypted(conn, pkt, p - pkt); + reply = write_encrypted(conn->fd, &conn->ap2_control_pairing, pkt, p - pkt); } else { reply = write(conn->fd, pkt, p - pkt); } @@ -2246,9 +2282,21 @@ void handle_configure(rtsp_conn_info *conn __attribute__((unused)), debug_log_rtsp_message(2, "POST /configure response:", resp); } -void handle_feedback(__attribute__((unused)) rtsp_conn_info *conn, - __attribute__((unused)) rtsp_message *req, +void handle_feedback(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *req, __attribute__((unused)) rtsp_message *resp) { + if (conn->airplay_stream_category == remote_control_stream) { + plist_t array_plist = plist_new_array(); + + plist_t response_plist = plist_new_dict(); + plist_dict_set_item(response_plist, "streams", array_plist); + + plist_to_bin(response_plist, &resp->content, &resp->contentlength); + plist_free(response_plist); + + msg_add_header(resp, "Content-Type", "application/x-apple-binary-plist"); + debug_log_rtsp_message(2, "FEEDBACK response (remote_control_stream):", resp); + } + /* not finished yet plist_t payload_plist = plist_new_dict(); plist_dict_set_item(payload_plist, "type", plist_new_uint(103)); @@ -2868,7 +2916,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) conn->connection_number, req); warn("Shairport Sync can not handle NTP streams."); } else if (conn->airplay_stream_category == remote_control_stream) { - debug_log_rtsp_message(2, "SETUP \"isRemoteControlOnly\" message", req); + debug_log_rtsp_message(2, "SETUP (no stream) \"isRemoteControlOnly\" message", req); // get a port to use as an event port // bind a new TCP port and get a socket @@ -2882,7 +2930,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) conn->connection_number, err); } - debug(2, "Connection %d: TCP Remote Control event port opened: %u.", + debug(2, "Connection %d SETUP (RC): TCP Remote Control event port opened: %u.", conn->connection_number, conn->local_event_port); if (conn->rtp_event_thread != NULL) debug(1, "previous rtp_event_thread allocation not freed, it seems."); @@ -2890,7 +2938,6 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) if (conn->rtp_event_thread == NULL) die("Couldn't allocate space for pthread_t"); pthread_create(conn->rtp_event_thread, NULL, &rtp_event_receiver, (void *)conn); - plist_dict_set_item(setupResponsePlist, "eventPort", plist_new_uint(conn->local_event_port)); plist_dict_set_item(setupResponsePlist, "timingPort", plist_new_uint(0)); @@ -3108,10 +3155,34 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) resp->respcode = 200; } else if (conn->airplay_stream_category == remote_control_stream) { debug(2, "Connection %d: SETUP: Remote Control Stream received.", conn->connection_number); - debug_log_rtsp_message(2, "Remote Control Stream stream (second) message", req); + + // get a port to use as an data port + // bind a new TCP port and get a socket + conn->local_data_port = 0; // any port + int err = + bind_socket_and_port(SOCK_STREAM, conn->connection_ip_family, conn->self_ip_string, + conn->self_scope_id, &conn->local_data_port, &conn->data_socket); + if (err) { + die("SETUP on Connection %d: Error %d: could not find a TCP port to use as a data " + "port", + conn->connection_number, err); + } + + debug(1, "Connection %d SETUP (RC): TCP Remote Control data port opened: %u.", + conn->connection_number, conn->local_data_port); + if (conn->rtp_data_thread != NULL) + debug(1, "previous rtp_data_thread allocation not freed, it seems."); + conn->rtp_data_thread = malloc(sizeof(pthread_t)); + if (conn->rtp_data_thread == NULL) + die("Couldn't allocate space for pthread_t"); + + pthread_create(conn->rtp_data_thread, NULL, &rtp_data_receiver, (void *)conn); + plist_t coreResponseDict = plist_new_dict(); plist_dict_set_item(coreResponseDict, "streamID", plist_new_uint(1)); plist_dict_set_item(coreResponseDict, "type", plist_new_uint(130)); + plist_dict_set_item(coreResponseDict, "dataPort", plist_new_uint(conn->local_data_port)); + plist_t coreResponseArray = plist_new_array(); plist_array_append_item(coreResponseArray, coreResponseDict); plist_dict_set_item(setupResponsePlist, "streams", coreResponseArray); @@ -4844,9 +4915,16 @@ static void *rtsp_conversation_thread_func(void *pconn) { (strcmp(req->method, "POST") == 0)) // the options message is very common, so don't log it until level 3 dl = 3; - debug(dl, "Connection %d: Received an RTSP Packet of type \"%s\":", conn->connection_number, - req->method), - debug_print_msg_headers(dl, req); + + if (conn->airplay_stream_category == remote_control_stream) { + debug(dl, "Connection %d (RC): Received an RTSP Packet of type \"%s\":", + conn->connection_number, req->method), + debug_log_rtsp_message(dl, NULL, req); + } else { + debug(dl, "Connection %d: Received an RTSP Packet of type \"%s\":", conn->connection_number, + req->method), + debug_log_rtsp_message(dl, NULL, req); + } apple_challenge(conn->fd, req, resp); hdr = msg_get_header(req, "CSeq"); if (hdr) @@ -4900,9 +4978,13 @@ static void *rtsp_conversation_thread_func(void *pconn) { } } } - debug(dl, "Connection %d: RTSP Response:", conn->connection_number); - debug_print_msg_headers(dl, resp); - + if (conn->airplay_stream_category == remote_control_stream) { + debug(dl, "Connection %d (RC): RTSP Response:", conn->connection_number); + debug_log_rtsp_message(dl, NULL, resp); + } else { + debug(dl, "Connection %d: RTSP Response:", conn->connection_number); + debug_log_rtsp_message(dl, NULL, resp); + } if (conn->stop == 0) { int err = msg_write_response(conn, resp); if (err) { @@ -5131,7 +5213,9 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) { t2 = secondary_txt_records; // second set of text records in AirPlay 2 only #endif build_bonjour_strings(NULL); // no conn yet - mdns_register(t1, t2); // note that the dacp thread could still be using the mdns stuff after all player threads have been terminated, so mdns_unregister can't be in the rtsp_listen_loop cleanup. + mdns_register(t1, t2); // note that the dacp thread could still be using the mdns stuff after + // all player threads have been terminated, so mdns_unregister can't be + // in the rtsp_listen_loop cleanup. pthread_setcancelstate(oldState, NULL); int acceptfd;