Rotate usage of UDP ports if a session is interrupted. Avoids out-of-date packets landing in a new session.

This commit is contained in:
Mike Brady
2018-11-23 13:29:09 +00:00
parent 3709ac8180
commit 093bf1dd46
7 changed files with 61 additions and 28 deletions
+17
View File
@@ -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; }
+11
View File
@@ -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, ...);
+3 -3
View File
@@ -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;
}
}
+12 -13
View File
@@ -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!");
}
+14 -8
View File
@@ -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);
+1 -1
View 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.
+3 -3
View 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 =