Skip to content

Commit c064b8b

Browse files
committed
Change order of some include file to facilitiate old Mac OS X builds. Check existence of TCP_KEEPINTVL before trying to use it. Fix a race condition with initial messages to the metadata queues. The race was that the queues and mutexes were definied in a thread, so could be delayed to after when the main process was using them.
1 parent 179c831 commit c064b8b

File tree

2 files changed

+56
-39
lines changed

2 files changed

+56
-39
lines changed

rtsp.c

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,8 @@ int pc_queue_add_item(pc_queue *the_queue, const void *the_stuff, int block) {
430430
} else
431431
rc = pthread_mutex_lock(&the_queue->pc_queue_lock);
432432
if (rc)
433-
debug(1, "Error locking for pc_queue_add_item");
433+
debug(1, "Error %d (\"%s\") locking for pc_queue_add_item. Block is %d.", rc, strerror(rc),
434+
block);
434435
pthread_cleanup_push(pc_queue_cleanup_handler, (void *)the_queue);
435436
// leave this out if you want this to return if the queue is already full
436437
// irrespective of the block flag.
@@ -1687,7 +1688,7 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r
16871688
hdr);
16881689
}
16891690
}
1690-
1691+
16911692
// In Stage 1, look for the DACP and Active-Remote
16921693
char *ar = msg_get_header(req, "Active-Remote");
16931694
if (ar) {
@@ -2101,8 +2102,8 @@ void handle_post(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
21012102
if (strcmp(req->path, "/feedback") == 0) {
21022103
resp->respcode = 501;
21032104
} else {
2104-
debug(1, "Connection %d: Airplay 1. Unhandled POST %s Content-Length %d", conn->connection_number,
2105-
req->path, req->contentlength);
2105+
debug(1, "Connection %d: Airplay 1. Unhandled POST %s Content-Length %d",
2106+
conn->connection_number, req->path, req->contentlength);
21062107
debug_log_rtsp_message(2, "POST request", req);
21072108
}
21082109
}
@@ -3085,7 +3086,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
30853086
// iap->ifa_name);
30863087
if ((iap->ifa_addr) && (iap->ifa_netmask) && (iap->ifa_flags & IFF_UP) &&
30873088
((iap->ifa_flags & IFF_LOOPBACK) == 0) &&
3088-
(config.interface == NULL || (strcmp(config.interface, iap->ifa_name) == 0))) {
3089+
(config.interface == NULL || (strcmp(config.interface, iap->ifa_name) == 0))) {
30893090
char buf[INET6_ADDRSTRLEN + 1]; // +1 for a NUL
30903091
memset(buf, 0, sizeof(buf));
30913092
if (iap->ifa_addr->sa_family == AF_INET6) {
@@ -4081,13 +4082,9 @@ void metadata_pack_cleanup_function(void *arg) {
40814082
void metadata_thread_cleanup_function(__attribute__((unused)) void *arg) {
40824083
// debug(2, "metadata_thread_cleanup_function called");
40834084
metadata_close();
4084-
pc_queue_delete(&metadata_queue);
40854085
}
40864086

40874087
void *metadata_thread_function(__attribute__((unused)) void *ignore) {
4088-
// create a pc_queue for passing information to a threaded metadata handler
4089-
pc_queue_init(&metadata_queue, (char *)&metadata_queue_items, sizeof(metadata_package),
4090-
metadata_queue_size, "pipe");
40914088
metadata_create_multicast_socket();
40924089
metadata_package pack;
40934090
pthread_cleanup_push(metadata_thread_cleanup_function, NULL);
@@ -4113,13 +4110,9 @@ void *metadata_thread_function(__attribute__((unused)) void *ignore) {
41134110
void metadata_multicast_thread_cleanup_function(__attribute__((unused)) void *arg) {
41144111
// debug(2, "metadata_multicast_thread_cleanup_function called");
41154112
metadata_delete_multicast_socket();
4116-
pc_queue_delete(&metadata_multicast_queue);
41174113
}
41184114

41194115
void *metadata_multicast_thread_function(__attribute__((unused)) void *ignore) {
4120-
// create a pc_queue for passing information to a threaded metadata handler
4121-
pc_queue_init(&metadata_multicast_queue, (char *)&metadata_multicast_queue_items,
4122-
sizeof(metadata_package), metadata_multicast_queue_size, "multicast");
41234116
metadata_create_multicast_socket();
41244117
metadata_package pack;
41254118
pthread_cleanup_push(metadata_multicast_thread_cleanup_function, NULL);
@@ -4154,13 +4147,9 @@ void metadata_hub_close(void) {}
41544147
void metadata_hub_thread_cleanup_function(__attribute__((unused)) void *arg) {
41554148
// debug(2, "metadata_hub_thread_cleanup_function called");
41564149
metadata_hub_close();
4157-
pc_queue_delete(&metadata_hub_queue);
41584150
}
41594151

41604152
void *metadata_hub_thread_function(__attribute__((unused)) void *ignore) {
4161-
// create a pc_queue for passing information to a threaded metadata handler
4162-
pc_queue_init(&metadata_hub_queue, (char *)&metadata_hub_queue_items, sizeof(metadata_package),
4163-
metadata_hub_queue_size, "hub");
41644153
metadata_package pack;
41654154
pthread_cleanup_push(metadata_hub_thread_cleanup_function, NULL);
41664155
while (1) {
@@ -4188,14 +4177,10 @@ void metadata_mqtt_close(void) {}
41884177
void metadata_mqtt_thread_cleanup_function(__attribute__((unused)) void *arg) {
41894178
// debug(2, "metadata_mqtt_thread_cleanup_function called");
41904179
metadata_mqtt_close();
4191-
pc_queue_delete(&metadata_mqtt_queue);
41924180
// debug(2, "metadata_mqtt_thread_cleanup_function done");
41934181
}
41944182

41954183
void *metadata_mqtt_thread_function(__attribute__((unused)) void *ignore) {
4196-
// create a pc_queue for passing information to a threaded metadata handler
4197-
pc_queue_init(&metadata_mqtt_queue, (char *)&metadata_mqtt_queue_items, sizeof(metadata_package),
4198-
metadata_mqtt_queue_size, "mqtt");
41994184
metadata_package pack;
42004185
pthread_cleanup_push(metadata_mqtt_thread_cleanup_function, NULL);
42014186
while (1) {
@@ -4242,24 +4227,39 @@ void metadata_init(void) {
42424227
if ((fd == -1) && (errno != ENXIO)) {
42434228
char errorstring[1024];
42444229
strerror_r(errno, (char *)errorstring, sizeof(errorstring));
4245-
debug(1, "metadata_hub_thread_function -- error %d (\"%s\") opening pipe: \"%s\".", errno,
4230+
debug(1, "metadata_init -- error %d (\"%s\") opening pipe: \"%s\".", errno,
42464231
(char *)errorstring, path);
42474232
warn("can not open metadata pipe -- error %d (\"%s\") opening pipe: \"%s\".", errno,
42484233
(char *)errorstring, path);
42494234
}
42504235
free(path);
4236+
4237+
// initialise the metadata queues first, otherwise the might be a race condition
4238+
// create a pc_queue for the metadata pipe
4239+
pc_queue_init(&metadata_queue, (char *)&metadata_queue_items, sizeof(metadata_package),
4240+
metadata_queue_size, "pipe");
4241+
42514242
if (pthread_create(&metadata_thread, NULL, metadata_thread_function, NULL) != 0)
42524243
debug(1, "Failed to create metadata thread!");
42534244

4245+
// create a pc_queue for the metadata_multicast_queue
4246+
pc_queue_init(&metadata_multicast_queue, (char *)&metadata_multicast_queue_items,
4247+
sizeof(metadata_package), metadata_multicast_queue_size, "multicast");
42544248
if (pthread_create(&metadata_multicast_thread, NULL, metadata_multicast_thread_function,
42554249
NULL) != 0)
42564250
debug(1, "Failed to create metadata multicast thread!");
42574251
}
42584252
#ifdef CONFIG_METADATA_HUB
4253+
// create a pc_queue for the metadata hub
4254+
pc_queue_init(&metadata_hub_queue, (char *)&metadata_hub_queue_items, sizeof(metadata_package),
4255+
metadata_hub_queue_size, "hub");
42594256
if (pthread_create(&metadata_hub_thread, NULL, metadata_hub_thread_function, NULL) != 0)
42604257
debug(1, "Failed to create metadata hub thread!");
42614258
#endif
42624259
#ifdef CONFIG_MQTT
4260+
// create a pc_queue for the MQTT handler
4261+
pc_queue_init(&metadata_mqtt_queue, (char *)&metadata_mqtt_queue_items, sizeof(metadata_package),
4262+
metadata_mqtt_queue_size, "mqtt");
42634263
if (pthread_create(&metadata_mqtt_thread, NULL, metadata_mqtt_thread_function, NULL) != 0)
42644264
debug(1, "Failed to create metadata mqtt thread!");
42654265
#endif
@@ -4273,26 +4273,30 @@ void metadata_stop(void) {
42734273
// debug(2, "metadata stop mqtt thread.");
42744274
pthread_cancel(metadata_mqtt_thread);
42754275
pthread_join(metadata_mqtt_thread, NULL);
4276+
pc_queue_delete(&metadata_mqtt_queue);
42764277
// debug(2, "metadata stop mqtt done.");
42774278
#endif
42784279
#ifdef CONFIG_METADATA_HUB
42794280
// debug(2, "metadata stop hub thread.");
42804281
pthread_cancel(metadata_hub_thread);
42814282
pthread_join(metadata_hub_thread, NULL);
42824283
// debug(2, "metadata stop hub done.");
4284+
pc_queue_delete(&metadata_hub_queue);
42834285
#endif
42844286
if (config.metadata_enabled) {
42854287
// debug(2, "metadata stop multicast thread.");
42864288
if (metadata_multicast_thread) {
42874289
pthread_cancel(metadata_multicast_thread);
42884290
pthread_join(metadata_multicast_thread, NULL);
42894291
// debug(2, "metadata stop multicast done.");
4292+
pc_queue_delete(&metadata_multicast_queue);
42904293
}
42914294
if (metadata_thread) {
42924295
// debug(2, "metadata stop metadata_thread thread.");
42934296
pthread_cancel(metadata_thread);
42944297
pthread_join(metadata_thread, NULL);
42954298
// debug(2, "metadata_stop finished successfully.");
4299+
pc_queue_delete(&metadata_queue);
42964300
}
42974301
}
42984302
}
@@ -4343,6 +4347,8 @@ int send_metadata_to_queue(pc_queue *queue, uint32_t type, uint32_t code, char *
43434347
if (data)
43444348
pack.data = memdup(data, length); // only if it's not a null
43454349
}
4350+
4351+
// debug(1, "send_metadata_to_queue %x/%x", type, code);
43464352
int rc = pc_queue_add_item(queue, &pack, block);
43474353
if (rc != 0) {
43484354
if (pack.carrier) {
@@ -5642,22 +5648,33 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) {
56425648
} else {
56435649
size_of_reply = sizeof(SOCKADDR);
56445650
if (getsockname(conn->fd, (struct sockaddr *)&conn->local, &size_of_reply) == 0) {
5651+
5652+
// skip this stuff in OpenBSD
56455653
#ifndef COMPILE_FOR_OPENBSD
56465654
// Thanks to https://holmeshe.me/network-essentials-setsockopt-SO_KEEPALIVE/ for this.
56475655

56485656
// turn on keepalive stuff -- wait for keepidle + (keepcnt * keepinttvl time) seconds
56495657
// before giving up an ETIMEOUT error is returned if the keepalive check fails
56505658

5659+
// if TCP_KEEPINTVL is defined, check a few times before declaring the line dead
5660+
// otherwise just wait a little while longer
5661+
5662+
#ifdef TCP_KEEPINTVL
56515663
int keepAliveIdleTime = 35; // wait this many seconds before checking for a dropped client
56525664
int keepAliveCount = 5; // check this many times
56535665
int keepAliveInterval = 5; // wait this many seconds between checks
5666+
#else
5667+
int keepAliveIdleTime = 60; // wait this many seconds before dropping a client
5668+
#endif
56545669

5670+
// --- the following is a bit too complicated
5671+
// decide to use IPPROTO_TCP or SOL_TCP
56555672
#if defined COMPILE_FOR_BSD || defined COMPILE_FOR_OSX
56565673
#define SOL_OPTION IPPROTO_TCP
56575674
#else
56585675
#define SOL_OPTION SOL_TCP
56595676
#endif
5660-
5677+
// decide to use TCP_KEEPALIVE or TCP_KEEPIDLE
56615678
#ifdef COMPILE_FOR_OSX
56625679
#define KEEP_ALIVE_OR_IDLE_OPTION TCP_KEEPALIVE
56635680
#else
@@ -5666,17 +5683,20 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) {
56665683

56675684
if (setsockopt(conn->fd, SOL_OPTION, KEEP_ALIVE_OR_IDLE_OPTION,
56685685
(void *)&keepAliveIdleTime, sizeof(keepAliveIdleTime))) {
5669-
debug(1, "can't set the keepidle wait time");
5686+
debug(1, "can't set the keepAliveIdleTime wait time");
56705687
}
5671-
5688+
// ---
5689+
// if TCP_KEEPINTVL is defined...
5690+
#ifdef TCP_KEEPINTVL
56725691
if (setsockopt(conn->fd, SOL_OPTION, TCP_KEEPCNT, (void *)&keepAliveCount,
56735692
sizeof(keepAliveCount))) {
5674-
debug(1, "can't set the keepidle missing count");
5693+
debug(1, "can't set the keepAliveCount count");
56755694
}
56765695
if (setsockopt(conn->fd, SOL_OPTION, TCP_KEEPINTVL, (void *)&keepAliveInterval,
56775696
sizeof(keepAliveInterval))) {
5678-
debug(1, "can't set the keepidle missing count interval");
5697+
debug(1, "can't set the keepAliveCount count interval");
56795698
};
5699+
#endif
56805700
#endif
56815701

56825702
// initialise the connection info
@@ -5736,8 +5756,8 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) {
57365756
pthread_cleanup_pop(1); // should never happen
57375757
} else {
57385758
die("could not establish a service on port %d -- program terminating. Is another instance of "
5739-
"Shairport Sync running on this device?",
5740-
config.port);
5759+
"Shairport Sync running on this device?",
5760+
config.port);
57415761
}
57425762
debug(1, "Oops -- fell out of the RTSP select loop");
57435763
pthread_exit(NULL);

shairport.c

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,8 +1207,8 @@ int parse_options(int argc, char **argv) {
12071207

12081208
} else {
12091209
if (config_error_type(&config_file_stuff) == CONFIG_ERR_FILE_IO)
1210-
die("Error reading configuration file \"%s\": \"%s\".",
1211-
config_file_real_path, config_error_text(&config_file_stuff));
1210+
die("Error reading configuration file \"%s\": \"%s\".", config_file_real_path,
1211+
config_error_text(&config_file_stuff));
12121212
else {
12131213
die("Line %d of the configuration file \"%s\":\n%s", config_error_line(&config_file_stuff),
12141214
config_error_file(&config_file_stuff), config_error_text(&config_file_stuff));
@@ -2110,12 +2110,9 @@ int main(int argc, char **argv) {
21102110

21112111
#ifdef COMPILE_FOR_OPENBSD
21122112
/* Any command to be executed at runtime? */
2113-
int run_cmds =
2114-
config.cmd_active_start != NULL ||
2115-
config.cmd_active_stop != NULL ||
2116-
config.cmd_set_volume != NULL ||
2117-
config.cmd_start != NULL ||
2118-
config.cmd_stop != NULL;
2113+
int run_cmds = config.cmd_active_start != NULL || config.cmd_active_stop != NULL ||
2114+
config.cmd_set_volume != NULL || config.cmd_start != NULL ||
2115+
config.cmd_stop != NULL;
21192116
#endif
21202117

21212118
// mDNS supports maximum of 63-character names (we append 13).
@@ -2381,11 +2378,11 @@ int main(int argc, char **argv) {
23812378
#ifdef COMPILE_FOR_OPENBSD
23822379
/* Past first and last sio_open(3), sndio(7) only needs "audio". */
23832380

2384-
# ifdef CONFIG_METADATA
2381+
#ifdef CONFIG_METADATA
23852382
/* Only coverart cache is created.
23862383
* Only metadata pipe is special. */
23872384
if (!config.metadata_enabled)
2388-
# endif
2385+
#endif
23892386
{
23902387
/* Drop "cpath dpath". */
23912388
if (run_cmds) {

0 commit comments

Comments
 (0)