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;
|
int socket_fd;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
|
connection_type_t type;
|
||||||
http_request_t *request;
|
http_request_t *request;
|
||||||
};
|
};
|
||||||
typedef struct http_connection_s http_connection_t;
|
typedef struct http_connection_s http_connection_t;
|
||||||
@@ -42,6 +43,7 @@ struct httpd_s {
|
|||||||
int max_connections;
|
int max_connections;
|
||||||
int open_connections;
|
int open_connections;
|
||||||
http_connection_t *connections;
|
http_connection_t *connections;
|
||||||
|
char nohold;
|
||||||
|
|
||||||
/* These variables only edited mutex locked */
|
/* These variables only edited mutex locked */
|
||||||
int running;
|
int running;
|
||||||
@@ -54,14 +56,43 @@ struct httpd_s {
|
|||||||
int server_fd6;
|
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_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;
|
httpd_t *httpd;
|
||||||
|
|
||||||
assert(logger);
|
assert(logger);
|
||||||
assert(callbacks);
|
assert(callbacks);
|
||||||
assert(max_connections > 0);
|
|
||||||
|
|
||||||
/* Allocate the httpd_t structure */
|
/* Allocate the httpd_t structure */
|
||||||
httpd = calloc(1, sizeof(httpd_t));
|
httpd = calloc(1, sizeof(httpd_t));
|
||||||
@@ -69,8 +100,10 @@ httpd_init(logger_t *logger, httpd_callbacks_t *callbacks, int max_connections)
|
|||||||
return NULL;
|
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) {
|
if (!httpd->connections) {
|
||||||
free(httpd);
|
free(httpd);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -111,6 +144,8 @@ httpd_remove_connection(httpd_t *httpd, http_connection_t *connection)
|
|||||||
shutdown(connection->socket_fd, SHUT_WR);
|
shutdown(connection->socket_fd, SHUT_WR);
|
||||||
closesocket(connection->socket_fd);
|
closesocket(connection->socket_fd);
|
||||||
connection->connected = 0;
|
connection->connected = 0;
|
||||||
|
connection->user_data = NULL;
|
||||||
|
connection->type = CONNECTION_TYPE_UNKNOWN;
|
||||||
httpd->open_connections--;
|
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");
|
logger_log(httpd->logger, LOGGER_INFO, "Max connections reached");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
user_data = httpd->callbacks.conn_init(httpd->callbacks.opaque, local, local_len, remote, remote_len, zone_id);
|
user_data = httpd->callbacks.conn_init(httpd->callbacks.opaque, local, local_len, remote, remote_len, zone_id);
|
||||||
if (!user_data) {
|
if (!user_data) {
|
||||||
logger_log(httpd->logger, LOGGER_ERR, "Error initializing HTTP request handler");
|
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].socket_fd = fd;
|
||||||
httpd->connections[i].connected = 1;
|
httpd->connections[i].connected = 1;
|
||||||
httpd->connections[i].user_data = user_data;
|
httpd->connections[i].user_data = user_data;
|
||||||
|
httpd->connections[i].type = CONNECTION_TYPE_UNKNOWN; //should not be necessary ...
|
||||||
return 0;
|
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);
|
remote = netutils_get_address(&remote_saddr, &remote_len, &remote_zone_id);
|
||||||
assert (local_zone_id == remote_zone_id);
|
assert (local_zone_id == remote_zone_id);
|
||||||
|
|
||||||
#ifdef NOHOLD
|
/* remove existing connections to make way for new connections, if http->nohold is set:
|
||||||
/* remove existing connections to make way for new connections:
|
* this will only occur if open_connections >= 2 and a connection with CONNECTION_TYPE_RAOP already exists */
|
||||||
* this will only occur if max_connections > 2 */
|
if (httpd->nohold && httpd->open_connections >= 2) {
|
||||||
if (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");
|
logger_log(httpd->logger, LOGGER_INFO, "Destroying current connections to allow connection by new client");
|
||||||
for (int i = 0; i<httpd->max_connections; i++) {
|
for (int i = 0; i<httpd->max_connections; i++) {
|
||||||
http_connection_t *connection = &httpd->connections[i];
|
http_connection_t *connection = &httpd->connections[i];
|
||||||
if (!connection->connected) {
|
if (!connection->connected) {
|
||||||
continue;
|
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);
|
ret = httpd_add_connection(httpd, fd, local, local_len, remote, remote_len, local_zone_id);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
@@ -476,4 +511,3 @@ httpd_stop(httpd_t *httpd)
|
|||||||
httpd->joined = 1;
|
httpd->joined = 1;
|
||||||
MUTEX_UNLOCK(httpd->run_mutex);
|
MUTEX_UNLOCK(httpd->run_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
19
lib/httpd.h
19
lib/httpd.h
@@ -21,17 +21,24 @@
|
|||||||
|
|
||||||
typedef struct httpd_s httpd_t;
|
typedef struct httpd_s httpd_t;
|
||||||
|
|
||||||
|
typedef enum connectype_type_e {
|
||||||
|
CONNECTION_TYPE_UNKNOWN,
|
||||||
|
CONNECTION_TYPE_RAOP
|
||||||
|
} connection_type_t;
|
||||||
|
|
||||||
struct httpd_callbacks_s {
|
struct httpd_callbacks_s {
|
||||||
void* opaque;
|
void* opaque;
|
||||||
void* (*conn_init)(void *opaque, unsigned char *local, int locallen, unsigned char *remote,
|
void* (*conn_init)(void *opaque, unsigned char *local, int locallen, unsigned char *remote,
|
||||||
int remotelen, unsigned int zone_id);
|
int remotelen, unsigned int zone_id);
|
||||||
void (*conn_request)(void *ptr, http_request_t *request, http_response_t **response);
|
void (*conn_request)(void *ptr, http_request_t *request, http_response_t **response);
|
||||||
void (*conn_destroy)(void *ptr);
|
void (*conn_destroy)(void *ptr);
|
||||||
};
|
};
|
||||||
typedef struct httpd_callbacks_s httpd_callbacks_t;
|
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);
|
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;
|
unsigned int zone_id;
|
||||||
|
|
||||||
|
connection_type_t connection_type;
|
||||||
|
|
||||||
bool have_active_remote;
|
bool have_active_remote;
|
||||||
};
|
};
|
||||||
typedef struct raop_conn_s raop_conn_t;
|
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);
|
memcpy(conn->remote, remote, remotelen);
|
||||||
|
|
||||||
conn->zone_id = zone_id;
|
conn->zone_id = zone_id;
|
||||||
|
|
||||||
conn->locallen = locallen;
|
conn->locallen = locallen;
|
||||||
conn->remotelen = remotelen;
|
conn->remotelen = remotelen;
|
||||||
|
|
||||||
|
conn->connection_type = CONNECTION_TYPE_UNKNOWN;
|
||||||
|
|
||||||
conn->have_active_remote = false;
|
conn->have_active_remote = false;
|
||||||
|
|
||||||
if (raop->callbacks.conn_init) {
|
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;
|
raop_conn_t *conn = ptr;
|
||||||
|
|
||||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "conn_request");
|
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 *method = http_request_get_method(request);
|
||||||
const char *url = http_request_get_url(request);
|
const char *url = http_request_get_url(request);
|
||||||
const char *protocol = http_request_get_protocol(request);
|
const char *protocol = http_request_get_protocol(request);
|
||||||
const char *cseq = http_request_get_header(request, "CSeq");
|
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) {
|
if (!conn->have_active_remote) {
|
||||||
const char *active_remote = http_request_get_header(request, "Active-Remote");
|
const char *active_remote = http_request_get_header(request, "Active-Remote");
|
||||||
if (active_remote) {
|
if (active_remote) {
|
||||||
@@ -264,6 +282,7 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) {
|
|||||||
if (handler != NULL) {
|
if (handler != NULL) {
|
||||||
handler(conn, request, *response, &response_data, &response_datalen);
|
handler(conn, request, *response, &response_data, &response_datalen);
|
||||||
}
|
}
|
||||||
|
finish:;
|
||||||
http_response_finish(*response, response_data, response_datalen);
|
http_response_finish(*response, response_data, response_datalen);
|
||||||
|
|
||||||
int len;
|
int len;
|
||||||
@@ -395,14 +414,11 @@ raop_init(raop_callbacks_t *callbacks) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
pairing_t *pairing;
|
||||||
httpd_t *httpd;
|
httpd_t *httpd;
|
||||||
httpd_callbacks_t httpd_cbs;
|
httpd_callbacks_t httpd_cbs;
|
||||||
|
|
||||||
assert(max_clients > 0);
|
|
||||||
assert(max_clients < 100);
|
|
||||||
|
|
||||||
/* create a new public key for pairing */
|
/* create a new public key for pairing */
|
||||||
int new_key;
|
int new_key;
|
||||||
pairing = pairing_init_generate(device_id, keyfile, &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;
|
httpd_cbs.conn_destroy = &conn_destroy;
|
||||||
|
|
||||||
/* Initialize the http daemon */
|
/* Initialize the http daemon */
|
||||||
httpd = httpd_init(raop->logger, &httpd_cbs, max_clients);
|
httpd = httpd_init(raop->logger, &httpd_cbs, nohold);
|
||||||
if (!httpd) {
|
if (!httpd) {
|
||||||
logger_log(raop->logger, LOGGER_ERR, "failed to initialize http daemon");
|
logger_log(raop->logger, LOGGER_ERR, "failed to initialize http daemon");
|
||||||
pairing_destroy(pairing);
|
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);
|
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 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_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 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);
|
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 bool debug_log = DEFAULT_DEBUG_LOG;
|
||||||
static int log_level = LOGGER_INFO;
|
static int log_level = LOGGER_INFO;
|
||||||
static bool bt709_fix = false;
|
static bool bt709_fix = false;
|
||||||
static int max_connections = 2;
|
static int nohold = 0;
|
||||||
static unsigned short raop_port;
|
static unsigned short raop_port;
|
||||||
static unsigned short airplay_port;
|
static unsigned short airplay_port;
|
||||||
static uint64_t remote_clock_offset = 0;
|
static uint64_t remote_clock_offset = 0;
|
||||||
@@ -1033,7 +1033,7 @@ static void parse_arguments (int argc, char *argv[]) {
|
|||||||
} else if (arg == "-bt709") {
|
} else if (arg == "-bt709") {
|
||||||
bt709_fix = true;
|
bt709_fix = true;
|
||||||
} else if (arg == "-nohold") {
|
} else if (arg == "-nohold") {
|
||||||
max_connections = 3;
|
nohold = 1;
|
||||||
} else if (arg == "-al") {
|
} else if (arg == "-al") {
|
||||||
int n;
|
int n;
|
||||||
char *end;
|
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_callback(raop, log_callback, NULL);
|
||||||
raop_set_log_level(raop, log_level);
|
raop_set_log_level(raop, log_level);
|
||||||
/* set max number of connections = 2 to protect against capture by new client */
|
/* set nohold = 1 to allow capture by new client */
|
||||||
if (raop_init2(raop, max_connections, mac_address.c_str(), keyfile.c_str())){
|
if (raop_init2(raop, nohold, mac_address.c_str(), keyfile.c_str())){
|
||||||
LOGE("Error initializing raop (2)!");
|
LOGE("Error initializing raop (2)!");
|
||||||
free (raop);
|
free (raop);
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
Reference in New Issue
Block a user