mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-14 00:04:13 +09:00
cleaned up -nohold feature + rejection of new connections when in use
(for compatibility with possible future video streaming additions)
This commit is contained in:
70
lib/httpd.c
70
lib/httpd.c
@@ -31,6 +31,7 @@ struct http_connection_s {
|
||||
|
||||
int socket_fd;
|
||||
void *user_data;
|
||||
connection_type_t type;
|
||||
http_request_t *request;
|
||||
};
|
||||
typedef struct http_connection_s http_connection_t;
|
||||
@@ -42,6 +43,7 @@ struct httpd_s {
|
||||
int max_connections;
|
||||
int open_connections;
|
||||
http_connection_t *connections;
|
||||
char nohold;
|
||||
|
||||
/* These variables only edited mutex locked */
|
||||
int running;
|
||||
@@ -54,14 +56,43 @@ struct httpd_s {
|
||||
int server_fd6;
|
||||
};
|
||||
|
||||
int
|
||||
httpd_set_connection_type (httpd_t *httpd, void *user_data, connection_type_t type) {
|
||||
for (int i = 0; i < httpd->max_connections; i++) {
|
||||
http_connection_t *connection = &httpd->connections[i];
|
||||
if (!connection->connected) {
|
||||
continue;
|
||||
}
|
||||
if (connection->user_data == user_data) {
|
||||
connection->type = type;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
httpd_count_connection_type (httpd_t *httpd, connection_type_t type) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < httpd->max_connections; i++) {
|
||||
http_connection_t *connection = &httpd->connections[i];
|
||||
if (!connection->connected) {
|
||||
continue;
|
||||
}
|
||||
if (connection->type == type) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#define MAX_CONNECTIONS 12 /* value used in AppleTV 3*/
|
||||
httpd_t *
|
||||
httpd_init(logger_t *logger, httpd_callbacks_t *callbacks, int max_connections)
|
||||
httpd_init(logger_t *logger, httpd_callbacks_t *callbacks, int nohold)
|
||||
{
|
||||
httpd_t *httpd;
|
||||
|
||||
assert(logger);
|
||||
assert(callbacks);
|
||||
assert(max_connections > 0);
|
||||
|
||||
/* Allocate the httpd_t structure */
|
||||
httpd = calloc(1, sizeof(httpd_t));
|
||||
@@ -69,8 +100,10 @@ httpd_init(logger_t *logger, httpd_callbacks_t *callbacks, int max_connections)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
httpd->max_connections = max_connections;
|
||||
httpd->connections = calloc(max_connections, sizeof(http_connection_t));
|
||||
|
||||
httpd->nohold = (nohold ? 1 : 0);
|
||||
httpd->max_connections = MAX_CONNECTIONS;
|
||||
httpd->connections = calloc(httpd->max_connections, sizeof(http_connection_t));
|
||||
if (!httpd->connections) {
|
||||
free(httpd);
|
||||
return NULL;
|
||||
@@ -111,6 +144,8 @@ httpd_remove_connection(httpd_t *httpd, http_connection_t *connection)
|
||||
shutdown(connection->socket_fd, SHUT_WR);
|
||||
closesocket(connection->socket_fd);
|
||||
connection->connected = 0;
|
||||
connection->user_data = NULL;
|
||||
connection->type = CONNECTION_TYPE_UNKNOWN;
|
||||
httpd->open_connections--;
|
||||
}
|
||||
|
||||
@@ -131,7 +166,6 @@ httpd_add_connection(httpd_t *httpd, int fd, unsigned char *local, int local_len
|
||||
logger_log(httpd->logger, LOGGER_INFO, "Max connections reached");
|
||||
return -1;
|
||||
}
|
||||
|
||||
user_data = httpd->callbacks.conn_init(httpd->callbacks.opaque, local, local_len, remote, remote_len, zone_id);
|
||||
if (!user_data) {
|
||||
logger_log(httpd->logger, LOGGER_ERR, "Error initializing HTTP request handler");
|
||||
@@ -142,6 +176,7 @@ httpd_add_connection(httpd_t *httpd, int fd, unsigned char *local, int local_len
|
||||
httpd->connections[i].socket_fd = fd;
|
||||
httpd->connections[i].connected = 1;
|
||||
httpd->connections[i].user_data = user_data;
|
||||
httpd->connections[i].type = CONNECTION_TYPE_UNKNOWN; //should not be necessary ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -178,20 +213,20 @@ httpd_accept_connection(httpd_t *httpd, int server_fd, int is_ipv6)
|
||||
remote = netutils_get_address(&remote_saddr, &remote_len, &remote_zone_id);
|
||||
assert (local_zone_id == remote_zone_id);
|
||||
|
||||
#ifdef NOHOLD
|
||||
/* remove existing connections to make way for new connections:
|
||||
* this will only occur if max_connections > 2 */
|
||||
if (httpd->open_connections >= 2) {
|
||||
logger_log(httpd->logger, LOGGER_INFO, "Destroying current connections to allow connection by new client");
|
||||
for (int i = 0; i<httpd->max_connections; i++) {
|
||||
http_connection_t *connection = &httpd->connections[i];
|
||||
if (!connection->connected) {
|
||||
continue;
|
||||
/* remove existing connections to make way for new connections, if http->nohold is set:
|
||||
* this will only occur if open_connections >= 2 and a connection with CONNECTION_TYPE_RAOP already exists */
|
||||
if (httpd->nohold && httpd->open_connections >= 2) {
|
||||
if (httpd_count_connection_type(httpd, CONNECTION_TYPE_RAOP)) {
|
||||
logger_log(httpd->logger, LOGGER_INFO, "Destroying current connections to allow connection by new client");
|
||||
for (int i = 0; i<httpd->max_connections; i++) {
|
||||
http_connection_t *connection = &httpd->connections[i];
|
||||
if (!connection->connected) {
|
||||
continue;
|
||||
}
|
||||
httpd_remove_connection(httpd, connection);
|
||||
}
|
||||
httpd_remove_connection(httpd, connection);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = httpd_add_connection(httpd, fd, local, local_len, remote, remote_len, local_zone_id);
|
||||
if (ret == -1) {
|
||||
@@ -476,4 +511,3 @@ httpd_stop(httpd_t *httpd)
|
||||
httpd->joined = 1;
|
||||
MUTEX_UNLOCK(httpd->run_mutex);
|
||||
}
|
||||
|
||||
|
||||
19
lib/httpd.h
19
lib/httpd.h
@@ -21,17 +21,24 @@
|
||||
|
||||
typedef struct httpd_s httpd_t;
|
||||
|
||||
typedef enum connectype_type_e {
|
||||
CONNECTION_TYPE_UNKNOWN,
|
||||
CONNECTION_TYPE_RAOP
|
||||
} connection_type_t;
|
||||
|
||||
struct httpd_callbacks_s {
|
||||
void* opaque;
|
||||
void* (*conn_init)(void *opaque, unsigned char *local, int locallen, unsigned char *remote,
|
||||
int remotelen, unsigned int zone_id);
|
||||
void (*conn_request)(void *ptr, http_request_t *request, http_response_t **response);
|
||||
void (*conn_destroy)(void *ptr);
|
||||
void* opaque;
|
||||
void* (*conn_init)(void *opaque, unsigned char *local, int locallen, unsigned char *remote,
|
||||
int remotelen, unsigned int zone_id);
|
||||
void (*conn_request)(void *ptr, http_request_t *request, http_response_t **response);
|
||||
void (*conn_destroy)(void *ptr);
|
||||
};
|
||||
typedef struct httpd_callbacks_s httpd_callbacks_t;
|
||||
|
||||
int httpd_set_connection_type (httpd_t *http, void *user_data, connection_type_t type);
|
||||
int httpd_count_connection_type (httpd_t *http, connection_type_t type);
|
||||
|
||||
httpd_t *httpd_init(logger_t *logger, httpd_callbacks_t *callbacks, int max_connections);
|
||||
httpd_t *httpd_init(logger_t *logger, httpd_callbacks_t *callbacks, int nohold);
|
||||
|
||||
int httpd_is_running(httpd_t *httpd);
|
||||
|
||||
|
||||
30
lib/raop.c
30
lib/raop.c
@@ -90,6 +90,8 @@ struct raop_conn_s {
|
||||
|
||||
unsigned int zone_id;
|
||||
|
||||
connection_type_t connection_type;
|
||||
|
||||
bool have_active_remote;
|
||||
};
|
||||
typedef struct raop_conn_s raop_conn_t;
|
||||
@@ -140,10 +142,12 @@ conn_init(void *opaque, unsigned char *local, int locallen, unsigned char *remot
|
||||
memcpy(conn->remote, remote, remotelen);
|
||||
|
||||
conn->zone_id = zone_id;
|
||||
|
||||
|
||||
conn->locallen = locallen;
|
||||
conn->remotelen = remotelen;
|
||||
|
||||
conn->connection_type = CONNECTION_TYPE_UNKNOWN;
|
||||
|
||||
conn->have_active_remote = false;
|
||||
|
||||
if (raop->callbacks.conn_init) {
|
||||
@@ -160,13 +164,27 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) {
|
||||
raop_conn_t *conn = ptr;
|
||||
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "conn_request");
|
||||
bool logger_debug = (logger_get_level(conn->raop->logger) >= LOGGER_DEBUG);
|
||||
|
||||
const char *method = http_request_get_method(request);
|
||||
const char *url = http_request_get_url(request);
|
||||
const char *protocol = http_request_get_protocol(request);
|
||||
const char *cseq = http_request_get_header(request, "CSeq");
|
||||
|
||||
bool logger_debug = (logger_get_level(conn->raop->logger) >= LOGGER_DEBUG);
|
||||
if (conn->connection_type == CONNECTION_TYPE_UNKNOWN) {
|
||||
if (httpd_count_connection_type(conn->raop->httpd, CONNECTION_TYPE_RAOP)) {
|
||||
char ipaddr[40];
|
||||
utils_ipaddress_to_string(conn->remotelen, conn->remote, conn->zone_id, ipaddr, (int) (sizeof(ipaddr)));
|
||||
logger_log(conn->raop->logger, LOGGER_WARNING, "rejecting new connection request from %s", ipaddr);
|
||||
*response = http_response_init("RTSP/1.0", 409, "Conflict: Server is connected to another client");
|
||||
http_response_add_header(*response, "CSeq", cseq);
|
||||
http_response_add_header(*response, "Server", "AirTunes/"GLOBAL_VERSION);
|
||||
goto finish;
|
||||
}
|
||||
httpd_set_connection_type(conn->raop->httpd, ptr, CONNECTION_TYPE_RAOP);
|
||||
conn->connection_type = CONNECTION_TYPE_RAOP;
|
||||
}
|
||||
|
||||
if (!conn->have_active_remote) {
|
||||
const char *active_remote = http_request_get_header(request, "Active-Remote");
|
||||
if (active_remote) {
|
||||
@@ -264,6 +282,7 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) {
|
||||
if (handler != NULL) {
|
||||
handler(conn, request, *response, &response_data, &response_datalen);
|
||||
}
|
||||
finish:;
|
||||
http_response_finish(*response, response_data, response_datalen);
|
||||
|
||||
int len;
|
||||
@@ -395,14 +414,11 @@ raop_init(raop_callbacks_t *callbacks) {
|
||||
}
|
||||
|
||||
int
|
||||
raop_init2(raop_t *raop, int max_clients, const char *device_id, const char *keyfile) {
|
||||
raop_init2(raop_t *raop, int nohold, const char *device_id, const char *keyfile) {
|
||||
pairing_t *pairing;
|
||||
httpd_t *httpd;
|
||||
httpd_callbacks_t httpd_cbs;
|
||||
|
||||
assert(max_clients > 0);
|
||||
assert(max_clients < 100);
|
||||
|
||||
/* create a new public key for pairing */
|
||||
int new_key;
|
||||
pairing = pairing_init_generate(device_id, keyfile, &new_key);
|
||||
@@ -433,7 +449,7 @@ raop_init2(raop_t *raop, int max_clients, const char *device_id, const char *key
|
||||
httpd_cbs.conn_destroy = &conn_destroy;
|
||||
|
||||
/* Initialize the http daemon */
|
||||
httpd = httpd_init(raop->logger, &httpd_cbs, max_clients);
|
||||
httpd = httpd_init(raop->logger, &httpd_cbs, nohold);
|
||||
if (!httpd) {
|
||||
logger_log(raop->logger, LOGGER_ERR, "failed to initialize http daemon");
|
||||
pairing_destroy(pairing);
|
||||
|
||||
@@ -69,7 +69,7 @@ raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const c
|
||||
int remote_addr_len, unsigned short timing_rport, timing_protocol_t *time_protocol);
|
||||
|
||||
RAOP_API raop_t *raop_init(raop_callbacks_t *callbacks);
|
||||
RAOP_API int raop_init2(raop_t *raop, int max_clients, const char *device_id, const char *keyfile);
|
||||
RAOP_API int raop_init2(raop_t *raop, int nohold, const char *device_id, const char *keyfile);
|
||||
RAOP_API void raop_set_log_level(raop_t *raop, int level);
|
||||
RAOP_API void raop_set_log_callback(raop_t *raop, raop_log_callback_t callback, void *cls);
|
||||
RAOP_API int raop_set_plist(raop_t *raop, const char *plist_item, const int value);
|
||||
|
||||
@@ -121,7 +121,7 @@ static unsigned short display[5] = {0}, tcp[3] = {0}, udp[3] = {0};
|
||||
static bool debug_log = DEFAULT_DEBUG_LOG;
|
||||
static int log_level = LOGGER_INFO;
|
||||
static bool bt709_fix = false;
|
||||
static int max_connections = 2;
|
||||
static int nohold = 0;
|
||||
static unsigned short raop_port;
|
||||
static unsigned short airplay_port;
|
||||
static uint64_t remote_clock_offset = 0;
|
||||
@@ -1033,7 +1033,7 @@ static void parse_arguments (int argc, char *argv[]) {
|
||||
} else if (arg == "-bt709") {
|
||||
bt709_fix = true;
|
||||
} else if (arg == "-nohold") {
|
||||
max_connections = 3;
|
||||
nohold = 1;
|
||||
} else if (arg == "-al") {
|
||||
int n;
|
||||
char *end;
|
||||
@@ -1825,8 +1825,8 @@ static int start_raop_server (unsigned short display[5], unsigned short tcp[3],
|
||||
}
|
||||
raop_set_log_callback(raop, log_callback, NULL);
|
||||
raop_set_log_level(raop, log_level);
|
||||
/* set max number of connections = 2 to protect against capture by new client */
|
||||
if (raop_init2(raop, max_connections, mac_address.c_str(), keyfile.c_str())){
|
||||
/* set nohold = 1 to allow capture by new client */
|
||||
if (raop_init2(raop, nohold, mac_address.c_str(), keyfile.c_str())){
|
||||
LOGE("Error initializing raop (2)!");
|
||||
free (raop);
|
||||
return -1;
|
||||
|
||||
Reference in New Issue
Block a user