From: Mike Brady Date: Fri, 23 Nov 2018 13:29:09 +0000 (+0000) Subject: Rotate usage of UDP ports if a session is interrupted. Avoids out-of-date packets... X-Git-Tag: 3.3RC0~149 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=093bf1dd46970a140a9199302bccb606930b0cf8;p=thirdparty%2Fshairport-sync.git Rotate usage of UDP ports if a session is interrupted. Avoids out-of-date packets landing in a new session. --- diff --git a/common.c b/common.c index b0b34b3e..f735dba4 100644 --- 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; } diff --git a/common.h b/common.h index 0a84b725..a043d0f7 100644 --- 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, ...); diff --git a/player.c b/player.c index 751621e4..f1837573 100644 --- 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 92837e58..4b71c0ee 100644 --- 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 db6e99f4..50bda29a 100644 --- 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); diff --git a/scripts/shairport-sync.conf b/scripts/shairport-sync.conf index 42c085b0..55ac4cbf 100644 --- a/scripts/shairport-sync.conf +++ b/scripts/shairport-sync.conf @@ -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. diff --git a/shairport.c b/shairport.c index 5e36e911..506f9feb 100644 --- a/shairport.c +++ b/shairport.c @@ -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 =