]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Tidy up write encrypted. Explore some of the remote_control connections. Not working.
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Thu, 23 Jun 2022 08:40:30 +0000 (09:40 +0100)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Thu, 23 Jun 2022 08:40:30 +0000 (09:40 +0100)
player.h
rtp.c
rtp.h
rtsp.c

index c4839fad4cca60ccaa71a7c9c61d22f58cb7d474..cda235e3c64287c8bf82af492716d68ab655004c 100644 (file)
--- 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 4066b7348c097eb2f2764e968dacd94fd9afd504..c729f286a5a1a1b908eaed5204c4738cb43f11ff 100644 (file)
--- 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 8eff06bb437c3bac6e37233cdc97851787228d89..825bca7294bd1b742928a97504e47564a6a17fdc 100644 (file)
--- 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 72cb5ef2f289431e0e94655f172ee87d5391f563..fa5c20ee658446c3dd8b7045bf74bd695482ca27 100644 (file)
--- 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;