]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Check for the existence of a session key when starting to play AP2, and drop the...
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Sat, 15 Oct 2022 12:31:32 +0000 (13:31 +0100)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Sat, 15 Oct 2022 12:31:32 +0000 (13:31 +0100)
rtsp.c

diff --git a/rtsp.c b/rtsp.c
index 62da82e5e0a4e3935650134f9fb8c827b7b9df79..6fb60824926a78133029258268d2b4f5283aad97 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -1501,6 +1501,7 @@ int msg_write_response(rtsp_conn_info *conn, rtsp_message *resp) {
                                    {404, "Not Found"},
                                    {451, "Unavailable"},
                                    {456, "Header Field Not Valid for Resource"},
+                                   {470, "Connection Authorization Required"},
                                    {500, "Internal Server Error"},
                                    {501, "Not Implemented"}};
   // 451 is really "Unavailable For Legal Reasons"!
@@ -3148,187 +3149,192 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
 
       plist_t streams_array = plist_new_array(); // to hold the ports and stuff
       plist_t stream0dict = plist_new_dict();
-      // more stuff
-      // set up a UDP control stream and thread and a UDP or TCP audio stream and thread
-
-      // bind a new UDP port and get a socket
-      conn->local_ap2_control_port = 0; // any port
-      err = bind_socket_and_port(SOCK_DGRAM, conn->connection_ip_family, conn->self_ip_string,
-                                 conn->self_scope_id, &conn->local_ap2_control_port,
-                                 &conn->ap2_control_socket);
-      if (err) {
-        die("Error %d: could not find a UDP port to use as an ap2_control port", err);
-      }
-      debug(2, "Connection %d: UDP control port opened: %u.", conn->connection_number,
-            conn->local_ap2_control_port);
-
-      pthread_create(&conn->rtp_ap2_control_thread, NULL, &rtp_ap2_control_receiver, (void *)conn);
 
-      // get the session key
+      // get the session key -- it must have one
 
       plist_t item = plist_dict_get_item(stream0, "shk"); // session key
-      uint64_t item_value = 0;
+      uint64_t item_value = 0; // the length
       plist_get_data_val(item, (char **)&conn->session_key, &item_value);
+      if (item_value != 0) {
 
-      // get the DACP-ID and Active Remote for remote control stuff
-
-      char *ar = msg_get_header(req, "Active-Remote");
-      if (ar) {
-        debug(3, "Connection %d: SETUP AP2 -- Active-Remote string seen: \"%s\".",
-              conn->connection_number, ar);
-        // get the active remote
-        if (conn->dacp_active_remote) // this is in case SETUP was previously called
-          free(conn->dacp_active_remote);
-        conn->dacp_active_remote = strdup(ar);
-#ifdef CONFIG_METADATA
-        send_metadata('ssnc', 'acre', ar, strlen(ar), req, 1);
-#endif
-      } else {
-        debug(1, "Connection %d: SETUP AP2 no Active-Remote information  the SETUP Record.",
-              conn->connection_number);
-        if (conn->dacp_active_remote) { // this is in case SETUP was previously called
-          free(conn->dacp_active_remote);
-          conn->dacp_active_remote = NULL;
-        }
-      }
-
-      ar = msg_get_header(req, "DACP-ID");
-      if (ar) {
-        debug(3, "Connection %d: SETUP AP2 -- DACP-ID string seen: \"%s\".",
-              conn->connection_number, ar);
-        if (conn->dacp_id) // this is in case SETUP was previously called
-          free(conn->dacp_id);
-        conn->dacp_id = strdup(ar);
-#ifdef CONFIG_METADATA
-        send_metadata('ssnc', 'daid', ar, strlen(ar), req, 1);
-#endif
-      } else {
-        debug(1, "Connection %d: SETUP AP2 doesn't include DACP-ID string information.",
-              conn->connection_number);
-        if (conn->dacp_id) { // this is in case SETUP was previously called
-          free(conn->dacp_id);
-          conn->dacp_id = NULL;
-        }
-      }
+        // more stuff
+        // set up a UDP control stream and thread and a UDP or TCP audio stream and thread
 
-      // now, get the type of the stream.
-      item = plist_dict_get_item(stream0, "type");
-      item_value = 0;
-      plist_get_uint_val(item, &item_value);
-
-      switch (item_value) {
-      case 96: {
-        debug(1, "Connection %d. AP2 Realtime Audio Stream.", conn->connection_number);
-        debug_log_rtsp_message(2, "Realtime Audio Stream SETUP incoming message", req);
-        // get_play_lock(conn);
-        conn->airplay_stream_type = realtime_stream;
         // bind a new UDP port and get a socket
-        conn->local_realtime_audio_port = 0; // any port
+        conn->local_ap2_control_port = 0; // any port
         err = bind_socket_and_port(SOCK_DGRAM, conn->connection_ip_family, conn->self_ip_string,
-                                   conn->self_scope_id, &conn->local_realtime_audio_port,
-                                   &conn->realtime_audio_socket);
+                                   conn->self_scope_id, &conn->local_ap2_control_port,
+                                   &conn->ap2_control_socket);
         if (err) {
-          die("Error %d: could not find a UDP port to use as a realtime_audio port", err);
+          die("Error %d: could not find a UDP port to use as an ap2_control port", err);
         }
-        debug(2, "Connection %d: UDP realtime audio port opened: %u.", conn->connection_number,
-              conn->local_realtime_audio_port);
-
-        pthread_create(&conn->rtp_realtime_audio_thread, NULL, &rtp_realtime_audio_receiver,
-                       (void *)conn);
-
-        plist_dict_set_item(stream0dict, "type", plist_new_uint(96));
-        plist_dict_set_item(stream0dict, "dataPort",
-                            plist_new_uint(conn->local_realtime_audio_port));
-
-        conn->stream.type = ast_apple_lossless;
-        debug(3, "An ALAC stream has been detected.");
-
-        // Set reasonable connection defaults
-        conn->stream.fmtp[0] = 96;
-        conn->stream.fmtp[1] = 352;
-        conn->stream.fmtp[2] = 0;
-        conn->stream.fmtp[3] = 16;
-        conn->stream.fmtp[4] = 40;
-        conn->stream.fmtp[5] = 10;
-        conn->stream.fmtp[6] = 14;
-        conn->stream.fmtp[7] = 2;
-        conn->stream.fmtp[8] = 255;
-        conn->stream.fmtp[9] = 0;
-        conn->stream.fmtp[10] = 0;
-        conn->stream.fmtp[11] = 44100;
-
-        // set the parameters of the player (as distinct from the parameters of the decoder --
-        // that's done later).
-        conn->max_frames_per_packet = conn->stream.fmtp[1]; // number of audio frames per packet.
-        conn->input_rate = conn->stream.fmtp[11];
-        conn->input_num_channels = conn->stream.fmtp[7];
-        conn->input_bit_depth = conn->stream.fmtp[3];
-        conn->input_bytes_per_frame = conn->input_num_channels * ((conn->input_bit_depth + 7) / 8);
-        debug(2, "Realtime Stream Play");
-        activity_monitor_signify_activity(1);
-        player_prepare_to_play(conn);
-        player_play(conn);
-
-        conn->rtp_running = 1; // hack!
-      } break;
-      case 103: {
-        debug(1, "Connection %d. AP2 Buffered Audio Stream.", conn->connection_number);
-        debug_log_rtsp_message(2, "Buffered Audio Stream SETUP incoming message", req);
-        // get_play_lock(conn);
-        conn->airplay_stream_type = buffered_stream;
-        // get needed stuff
-
-        // bind a new TCP port and get a socket
-        conn->local_buffered_audio_port = 0; // any port
-        err = bind_socket_and_port(SOCK_STREAM, conn->connection_ip_family, conn->self_ip_string,
-                                   conn->self_scope_id, &conn->local_buffered_audio_port,
-                                   &conn->buffered_audio_socket);
-        if (err) {
-          die("SETUP on Connection %d: Error %d: could not find a TCP port to use as a "
-              "buffered_audio port",
-              conn->connection_number, err);
+        debug(2, "Connection %d: UDP control port opened: %u.", conn->connection_number,
+              conn->local_ap2_control_port);
+
+        pthread_create(&conn->rtp_ap2_control_thread, NULL, &rtp_ap2_control_receiver, (void *)conn);
+
+        // get the DACP-ID and Active Remote for remote control stuff
+
+        char *ar = msg_get_header(req, "Active-Remote");
+        if (ar) {
+          debug(3, "Connection %d: SETUP AP2 -- Active-Remote string seen: \"%s\".",
+                conn->connection_number, ar);
+          // get the active remote
+          if (conn->dacp_active_remote) // this is in case SETUP was previously called
+            free(conn->dacp_active_remote);
+          conn->dacp_active_remote = strdup(ar);
+  #ifdef CONFIG_METADATA
+          send_metadata('ssnc', 'acre', ar, strlen(ar), req, 1);
+  #endif
+        } else {
+          debug(1, "Connection %d: SETUP AP2 no Active-Remote information  the SETUP Record.",
+                conn->connection_number);
+          if (conn->dacp_active_remote) { // this is in case SETUP was previously called
+            free(conn->dacp_active_remote);
+            conn->dacp_active_remote = NULL;
+          }
         }
 
-        debug(2, "Connection %d: TCP Buffered Audio port opened: %u.", conn->connection_number,
-              conn->local_buffered_audio_port);
-
-        // hack.
-        conn->max_frames_per_packet = 352; // number of audio frames per packet.
-        conn->input_rate = 44100;          // we are stuck with this for the moment.
-        conn->input_num_channels = 2;
-        conn->input_bit_depth = 16;
-        conn->input_bytes_per_frame = conn->input_num_channels * ((conn->input_bit_depth + 7) / 8);
-        activity_monitor_signify_activity(1);
-        player_prepare_to_play(
-            conn); // get capabilities of DAC before creating the buffered audio thread
+        ar = msg_get_header(req, "DACP-ID");
+        if (ar) {
+          debug(3, "Connection %d: SETUP AP2 -- DACP-ID string seen: \"%s\".",
+                conn->connection_number, ar);
+          if (conn->dacp_id) // this is in case SETUP was previously called
+            free(conn->dacp_id);
+          conn->dacp_id = strdup(ar);
+  #ifdef CONFIG_METADATA
+          send_metadata('ssnc', 'daid', ar, strlen(ar), req, 1);
+  #endif
+        } else {
+          debug(1, "Connection %d: SETUP AP2 doesn't include DACP-ID string information.",
+                conn->connection_number);
+          if (conn->dacp_id) { // this is in case SETUP was previously called
+            free(conn->dacp_id);
+            conn->dacp_id = NULL;
+          }
+        }
 
-        pthread_create(&conn->rtp_buffered_audio_thread, NULL, &rtp_buffered_audio_processor,
-                       (void *)conn);
+        // now, get the type of the stream.
+        item = plist_dict_get_item(stream0, "type");
+        item_value = 0;
+        plist_get_uint_val(item, &item_value);
+
+        switch (item_value) {
+        case 96: {
+          debug(1, "Connection %d. AP2 Realtime Audio Stream.", conn->connection_number);
+          debug_log_rtsp_message(2, "Realtime Audio Stream SETUP incoming message", req);
+          // get_play_lock(conn);
+          conn->airplay_stream_type = realtime_stream;
+          // bind a new UDP port and get a socket
+          conn->local_realtime_audio_port = 0; // any port
+          err = bind_socket_and_port(SOCK_DGRAM, conn->connection_ip_family, conn->self_ip_string,
+                                     conn->self_scope_id, &conn->local_realtime_audio_port,
+                                     &conn->realtime_audio_socket);
+          if (err) {
+            die("Error %d: could not find a UDP port to use as a realtime_audio port", err);
+          }
+          debug(2, "Connection %d: UDP realtime audio port opened: %u.", conn->connection_number,
+                conn->local_realtime_audio_port);
+
+          pthread_create(&conn->rtp_realtime_audio_thread, NULL, &rtp_realtime_audio_receiver,
+                         (void *)conn);
+
+          plist_dict_set_item(stream0dict, "type", plist_new_uint(96));
+          plist_dict_set_item(stream0dict, "dataPort",
+                              plist_new_uint(conn->local_realtime_audio_port));
+
+          conn->stream.type = ast_apple_lossless;
+          debug(3, "An ALAC stream has been detected.");
+
+          // Set reasonable connection defaults
+          conn->stream.fmtp[0] = 96;
+          conn->stream.fmtp[1] = 352;
+          conn->stream.fmtp[2] = 0;
+          conn->stream.fmtp[3] = 16;
+          conn->stream.fmtp[4] = 40;
+          conn->stream.fmtp[5] = 10;
+          conn->stream.fmtp[6] = 14;
+          conn->stream.fmtp[7] = 2;
+          conn->stream.fmtp[8] = 255;
+          conn->stream.fmtp[9] = 0;
+          conn->stream.fmtp[10] = 0;
+          conn->stream.fmtp[11] = 44100;
+
+          // set the parameters of the player (as distinct from the parameters of the decoder --
+          // that's done later).
+          conn->max_frames_per_packet = conn->stream.fmtp[1]; // number of audio frames per packet.
+          conn->input_rate = conn->stream.fmtp[11];
+          conn->input_num_channels = conn->stream.fmtp[7];
+          conn->input_bit_depth = conn->stream.fmtp[3];
+          conn->input_bytes_per_frame = conn->input_num_channels * ((conn->input_bit_depth + 7) / 8);
+          debug(2, "Realtime Stream Play");
+          activity_monitor_signify_activity(1);
+          player_prepare_to_play(conn);
+          player_play(conn);
+
+          conn->rtp_running = 1; // hack!
+        } break;
+        case 103: {
+          debug(1, "Connection %d. AP2 Buffered Audio Stream.", conn->connection_number);
+          debug_log_rtsp_message(2, "Buffered Audio Stream SETUP incoming message", req);
+          // get_play_lock(conn);
+          conn->airplay_stream_type = buffered_stream;
+          // get needed stuff
 
-        plist_dict_set_item(stream0dict, "type", plist_new_uint(103));
-        plist_dict_set_item(stream0dict, "dataPort",
-                            plist_new_uint(conn->local_buffered_audio_port));
-        plist_dict_set_item(stream0dict, "audioBufferSize",
-                            plist_new_uint(conn->ap2_audio_buffer_size));
+          // bind a new TCP port and get a socket
+          conn->local_buffered_audio_port = 0; // any port
+          err = bind_socket_and_port(SOCK_STREAM, conn->connection_ip_family, conn->self_ip_string,
+                                     conn->self_scope_id, &conn->local_buffered_audio_port,
+                                     &conn->buffered_audio_socket);
+          if (err) {
+            die("SETUP on Connection %d: Error %d: could not find a TCP port to use as a "
+                "buffered_audio port",
+                conn->connection_number, err);
+          }
 
-        // this should be cancelled by an activity_monitor_signify_activity(1)
-        // call in the SETRATEANCHORI handler, which should come up right away
-        activity_monitor_signify_activity(0);
-        player_play(conn);
-
-        conn->rtp_running = 1; // hack!
-      } break;
-      default:
-        debug(1, "SETUP on Connection %d: Unhandled stream type %" PRIu64 ".",
-              conn->connection_number, item_value);
-        debug_log_rtsp_message(1, "Unhandled stream type incoming message", req);
-      }
+          debug(2, "Connection %d: TCP Buffered Audio port opened: %u.", conn->connection_number,
+                conn->local_buffered_audio_port);
+
+          // hack.
+          conn->max_frames_per_packet = 352; // number of audio frames per packet.
+          conn->input_rate = 44100;          // we are stuck with this for the moment.
+          conn->input_num_channels = 2;
+          conn->input_bit_depth = 16;
+          conn->input_bytes_per_frame = conn->input_num_channels * ((conn->input_bit_depth + 7) / 8);
+          activity_monitor_signify_activity(1);
+          player_prepare_to_play(
+              conn); // get capabilities of DAC before creating the buffered audio thread
+
+          pthread_create(&conn->rtp_buffered_audio_thread, NULL, &rtp_buffered_audio_processor,
+                         (void *)conn);
+
+          plist_dict_set_item(stream0dict, "type", plist_new_uint(103));
+          plist_dict_set_item(stream0dict, "dataPort",
+                              plist_new_uint(conn->local_buffered_audio_port));
+          plist_dict_set_item(stream0dict, "audioBufferSize",
+                              plist_new_uint(conn->ap2_audio_buffer_size));
+
+          // this should be cancelled by an activity_monitor_signify_activity(1)
+          // call in the SETRATEANCHORI handler, which should come up right away
+          activity_monitor_signify_activity(0);
+          player_play(conn);
+
+          conn->rtp_running = 1; // hack!
+        } break;
+        default:
+          debug(1, "SETUP on Connection %d: Unhandled stream type %" PRIu64 ".",
+                conn->connection_number, item_value);
+          debug_log_rtsp_message(1, "Unhandled stream type incoming message", req);
+        }
 
-      plist_dict_set_item(stream0dict, "controlPort", plist_new_uint(conn->local_ap2_control_port));
+        plist_dict_set_item(stream0dict, "controlPort", plist_new_uint(conn->local_ap2_control_port));
 
-      plist_array_append_item(streams_array, stream0dict);
-      plist_dict_set_item(setupResponsePlist, "streams", streams_array);
-      resp->respcode = 200;
+        plist_array_append_item(streams_array, stream0dict);
+        plist_dict_set_item(setupResponsePlist, "streams", streams_array);
+        resp->respcode = 200;
+      } else {
+        warn("this stream can not be played because a session key is missing.");
+      }
     } else if (conn->airplay_stream_category == remote_control_stream) {
       debug(2, "Connection %d (RC): SETUP: Remote Control Stream received from %s.",
             conn->connection_number, conn->client_ip_string);
@@ -4303,7 +4309,7 @@ static void handle_get_parameter(__attribute__((unused)) rtsp_conn_info *conn, r
 
   if ((req->content) && (req->contentlength == strlen("volume\r\n")) &&
       strstr(req->content, "volume") == req->content) {
-    debug(2, "Connection %d: Current volume (%.6f) requested", conn->connection_number,
+    debug(1, "Connection %d: Current volume (%.6f) requested", conn->connection_number,
           config.airplay_volume);
     char *p = malloc(128); // will be automatically deallocated with the response is deleted
     if (p) {