]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Rotate usage of UDP ports if a session is interrupted. Avoids out-of-date packets...
authorMike Brady <mikebrady@eircom.net>
Fri, 23 Nov 2018 13:29:09 +0000 (13:29 +0000)
committerMike Brady <mikebrady@eircom.net>
Fri, 23 Nov 2018 13:29:09 +0000 (13:29 +0000)
common.c
common.h
player.c
rtp.c
rtsp.c
scripts/shairport-sync.conf
shairport.c

index b0b34b3eb04bdaf2877922a5830a22c89ba094fe..f735dba43e9c177a92ea9ef2f8aa8acdbc3305ca 100644 (file)
--- a/common.c
+++ b/common.c
@@ -94,6 +94,23 @@ volatile int debuglev = 0;
 
 sigset_t pselect_sigset;
 
+static uint16_t UDPPortIndex = 0;
+
+void resetFreeUDPPort() {
+       UDPPortIndex = 0;
+}
+
+uint16_t nextFreeUDPPort() {
+       
+       if (UDPPortIndex == 0)
+               UDPPortIndex = config.udp_port_base;
+       else if (UDPPortIndex == (config.udp_port_base + config.udp_port_range))
+               UDPPortIndex = config.udp_port_base;
+       else
+               UDPPortIndex++;
+       return UDPPortIndex;
+}
+
 int get_requested_connection_state_to_output() { return requested_connection_state_to_output; }
 
 void set_requested_connection_state_to_output(int v) { requested_connection_state_to_output = v; }
index 0a84b725735f9ea115f1f6e0d40eb6c36f563c49..a043d0f78f8313455bd9c3b0e135d5e1eb2de3eb 100644 (file)
--- a/common.h
+++ b/common.h
@@ -243,6 +243,17 @@ void r64arrayinit();
 uint64_t ranarray64u();
 int64_t ranarray64i();
 
+// if you are breaking in to a session, you need to avoid the ports of the current session
+// if you are law-abiding, then you can reuse the ports.
+// so, you can reset the free UDP ports minder when you're legit, and leave it otherwise
+
+// the downside of using different ports each time is that it might make the firewall
+// rules a bit more complex, as they need to allow more than the minimum three ports.
+// a range of 10 is suggested anyway
+
+void resetFreeUDPPort();
+uint16_t nextFreeUDPPort();
+
 volatile int debuglev;
 void die(const char *format, ...);
 void warn(const char *format, ...);
index 751621e4021711c70fe1536d90e72b5d32a7fda9..f18375738ac022e8c03883c305e69d7465ff8fd9 100644 (file)
--- a/player.c
+++ b/player.c
@@ -457,7 +457,7 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, uint8_t *data, in
     if ((conn->flush_rtp_timestamp != 0) && (actual_timestamp != conn->flush_rtp_timestamp) &&
         (modulo_32_offset(actual_timestamp, conn->flush_rtp_timestamp) <
          conn->input_rate * 10)) { // if it's less than 10 seconds
-      debug(2, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %" PRIu32
+      debug(3, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %" PRIu32
                ", flushing to "
                "timestamp: %" PRIu32 ".",
             seqno, actual_timestamp, conn->flush_rtp_timestamp);
@@ -859,7 +859,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
             (curframe->given_timestamp != conn->flush_rtp_timestamp) &&
             (modulo_32_offset(curframe->given_timestamp, conn->flush_rtp_timestamp) <
              conn->input_rate * 10)) { // if it's less than ten seconds
-          debug(2, "Dropping flushed packet in buffer_get_frame, seqno %u, timestamp %" PRIu32
+          debug(3, "Dropping flushed packet in buffer_get_frame, seqno %u, timestamp %" PRIu32
                    ", flushing to "
                    "timestamp: %" PRIu32 ".",
                 curframe->sequence_number, curframe->given_timestamp, conn->flush_rtp_timestamp);
@@ -874,7 +874,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
              conn->input_rate / 5) &&
             (modulo_32_offset(conn->flush_rtp_timestamp, curframe->given_timestamp) <
              conn->input_rate * 10)) {
-          debug(2, "Dropping flush request in buffer_get_frame");
+          debug(3, "Dropping flush request in buffer_get_frame");
           conn->flush_rtp_timestamp = 0;
         }
       }
diff --git a/rtp.c b/rtp.c
index 92837e5865209ed0abe022b1beae6ad3e33a8409..4b71c0eeaae07e8b6a229817ad4cbc0e0cd9a35c 100644 (file)
--- a/rtp.c
+++ b/rtp.c
@@ -129,11 +129,8 @@ void *rtp_audio_receiver(void *arg) {
   ssize_t nread;
   while (1) {
     nread = recv(conn->audio_socket, packet, sizeof(packet), 0);
-    
+
     frame_count++;
-    if (frame_count<10)
-      debug(1,"Recv'ed %d bytes. First two bytes are %02X,%02X ",nread,packet[0],packet[1]);
-   else {
 
     uint64_t local_time_now_fp = get_absolute_time_in_fp();
     if (time_of_previous_packet_fp) {
@@ -200,8 +197,8 @@ void *rtp_audio_receiver(void *arg) {
 
         uint32_t actual_timestamp = ntohl(*(uint32_t *)(pktp + 4));
         
-        uint32_t ssid = ntohl(*(uint32_t *)(pktp + 8));
-        debug(1, "Audio packet SSID: %08X,%u", ssid,ssid);
+        // uint32_t ssid = ntohl(*(uint32_t *)(pktp + 8));
+        // debug(1, "Audio packet SSID: %08X,%u", ssid,ssid);
 
         // if (packet[1]&0x10)
         //     debug(1,"Audio packet Extension bit set.");
@@ -229,7 +226,6 @@ void *rtp_audio_receiver(void *arg) {
     } else {
       debug(1, "Error receiving an audio packet.");
     }
-    }
   }
 
   /*
@@ -605,10 +601,10 @@ void *rtp_timing_receiver(void *arg) {
           (drand48() > config.diagnostic_drop_packet_fraction)) {
         arrival_time = get_absolute_time_in_fp();
 
-        ssize_t plen = nread;
+        // ssize_t plen = nread;
         // debug(1,"Packet Received on Timing Port.");
         if (packet[1] == 0xd3) { // timing reply
-          
+          /*
           char obf[4096];
           char *obfp = obf;
           int obfc;
@@ -618,7 +614,7 @@ void *rtp_timing_receiver(void *arg) {
           };
           *obfp=0;
           debug(1,"Timing Packet Received: \"%s\"",obf);
-          
+          */
 
           // arrival_time = ((uint64_t)att.tv_sec<<32)+((uint64_t)att.tv_nsec<<32)/1000000000;
           // departure_time = ((uint64_t)dtt.tv_sec<<32)+((uint64_t)dtt.tv_nsec<<32)/1000000000;
@@ -855,14 +851,17 @@ void *rtp_timing_receiver(void *arg) {
 static uint16_t bind_port(int ip_family, const char *self_ip_address, uint32_t scope_id,
                           int *sock) {
   // look for a port in the range, if any was specified.
-  uint16_t desired_port = config.udp_port_base;
   int ret = 0;
 
   int local_socket = socket(ip_family, SOCK_DGRAM, IPPROTO_UDP);
   if (local_socket == -1)
     die("Could not allocate a socket.");
   SOCKADDR myaddr;
+  int tryCount = 0;
+  uint16_t desired_port;
   do {
+       tryCount++;
+         desired_port = nextFreeUDPPort();
     memset(&myaddr, 0, sizeof(myaddr));
     if (ip_family == AF_INET) {
       struct sockaddr_in *sa = (struct sockaddr_in *)&myaddr;
@@ -883,13 +882,13 @@ static uint16_t bind_port(int ip_family, const char *self_ip_address, uint32_t s
 #endif
 
   } while ((ret < 0) && (errno == EADDRINUSE) && (desired_port != 0) &&
-           (++desired_port < config.udp_port_base + config.udp_port_range));
+           (tryCount < config.udp_port_range));
 
   // debug(1,"UDP port chosen: %d.",desired_port);
 
   if (ret < 0) {
     close(local_socket);
-    die("error: could not bind a UDP port! Check the udp_port_range is large enough (>= 10) or "
+    die("error: could not bind a UDP port! Check the udp_port_range is large enough -- it must be at least 3, and 10 or more is suggested -- or "
         "check for restrictive firewall settings or a bad router!");
   }
 
diff --git a/rtsp.c b/rtsp.c
index db6e99f46a416edffdc350d435e5dbccdf4fbb11..50bda29a8cbd4c99f2061374b2cf2248589247d1 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -459,7 +459,7 @@ int msg_handle_line(rtsp_message **pmsg, char *line) {
     char *sp, *p;
     sp = NULL; // this is to quieten a compiler warning
 
-    debug(1, "received request: %s", line);
+    debug(3, "RTSP Message Received: \"%s\".", line);
 
     p = strtok_r(line, " ", &sp);
     if (!p)
@@ -1525,7 +1525,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
   
   
   int have_the_player = 0;
-  int should_wait = 0;
+  int should_wait = 0; // this will be true if you're trying to break in to the current session
   
   // try to become the current playing_conn
   
@@ -1568,7 +1568,6 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
 
     if (have_the_player == 1) {
       debug(1, "Connection %d: ANNOUNCE got the player", conn->connection_number);
-      usleep(2000000); // this is just to let everything settle a bit
     } else {
       debug(1, "Connection %d: ANNOUNCE failed to get the player", conn->connection_number);
     }
@@ -1577,17 +1576,25 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
   if (have_the_player) {
     debug(3, "RTSP conversation thread %d has acquired play lock.", conn->connection_number);
     
+    // now, if this new session did not break in, then it's okay to reset the next UDP ports
+    // to the start of the range
+    
+    if (should_wait == 0) { // will be zero if it didn't need to wait to break in
+       resetFreeUDPPort();
+    }
+    
+    /*
     {
       char *cp = req->content;
       int cp_left = req->contentlength;
       while (cp_left > 1) {
         if (strlen(cp) != 0)
-          warn("    %s", cp);
+          debug(1,">>>>>> %s", cp);
         cp += strlen(cp) + 1;
         cp_left -= strlen(cp) + 1;
       }
     }
-
+*/
     
     
     resp->respcode = 456; // 456 - Header Field Not Valid for Resource
@@ -1637,7 +1644,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
     
     if (pssid) {
       uint32_t ssid = uatoi(pssid);
-      debug(1, "Synchronisation Source Identifier: %08X,%u", ssid,ssid);
+      debug(3, "Synchronisation Source Identifier: %08X,%u", ssid,ssid);
     }    
 
     if (pminlatency) {
@@ -1992,7 +1999,6 @@ void rtsp_conversation_thread_cleanup_function(void *arg) {
     // debug(1, "Connection %d: closing fd %d.",
     //    conn->connection_number,conn->fd);
     close(conn->fd);
-    usleep(1000000);
   }
   if (conn->auth_nonce) {
     free(conn->auth_nonce);
@@ -2019,7 +2025,7 @@ void rtsp_conversation_thread_cleanup_function(void *arg) {
 
   debug_mutex_lock(&playing_conn_lock, 1000000 , 3); //get it
   if (playing_conn == conn) {
-    debug(1, "Connection %d: Unlocking play lock.", conn->connection_number);
+    debug(3, "Connection %d: Unlocking play lock.", conn->connection_number);
     playing_conn = NULL;
   }
   debug_mutex_unlock(&playing_conn_lock, 3);
index 42c085b01881f27a9b14e02bd9d17b302df46355..55ac4cbfca2d151e02d51a5c756317728009e0a5 100644 (file)
@@ -18,7 +18,7 @@ general =
 //     mdns_backend = "avahi"; // Run "shairport-sync -h" to get a list of all mdns_backends. The default is the first one.
 //     port = 5000; // Listen for service requests on this port
 //     udp_port_base = 6001; // start allocating UDP ports from this port number when needed
-//     udp_port_range = 100; // look for free ports in this number of places, starting at the UDP port base. Allow at least 10, though only three are needed in a steady state.
+//     udp_port_range = 10; // look for free ports in this number of places, starting at the UDP port base. Allow at least 10, though only three are needed in a steady state.
 //     drift_tolerance_in_seconds = 0.002; // allow a timing error of this number of seconds of drift away from exact synchronisation before attempting to correct it
 //     resync_threshold_in_seconds = 0.050; // a synchronisation error greater than this number of seconds will cause resynchronisation; 0 disables it
 //     ignore_volume_control = "no"; // set this to "yes" if you want the volume to be at 100% no matter what the source's volume control is set to.
index 5e36e911b5582fa3cde768c59adcefa6ffcc8a3c..506f9febe7d5312b6866816813273646b848bbe0 100644 (file)
@@ -419,8 +419,8 @@ int parse_options(int argc, char **argv) {
       /* Get the udp port range setting. This is number of ports that will be tried for free ports ,
        * starting at the port base. Only three ports are needed. */
       if (config_lookup_int(config.cfg, "general.udp_port_range", &value)) {
-        if ((value < 0) || (value > 65535))
-          die("Invalid port range  \"%sd\". It should be between 0 and 65535, default is 100",
+        if ((value < 3) || (value > 65535))
+          die("Invalid port range  \"%sd\". It should be between 3 and 65535, default is 10",
               value);
         else
           config.udp_port_range = value;
@@ -1234,7 +1234,7 @@ int main(int argc, char **argv) {
       1); // we expect to be able to connect to the output device
   config.audio_backend_buffer_desired_length = 6615; // 0.15 seconds.
   config.udp_port_base = 6001;
-  config.udp_port_range = 100;
+  config.udp_port_range = 10;
   config.output_format = SPS_FORMAT_S16; // default
   config.output_rate = 44100;            // default
   config.decoders_supported =