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:
@@ -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; }
|
||||
|
||||
@@ -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, ...);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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!");
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user