From 44365fe59c0efa5ee416b2cbc6a560e264b1a4a0 Mon Sep 17 00:00:00 2001 From: "F. Duncanh" Date: Thu, 23 Nov 2023 20:26:21 -0500 Subject: [PATCH] add infrastructure for pair-pin-start, + changing features --- lib/crypto.c | 6 +++- lib/dnssd.c | 79 +++++++++++++++++++++++++++++++++++++++++---- lib/dnssd.h | 8 +++-- lib/dnssdint.h | 16 ++++----- lib/pairing.c | 20 ++++++++++++ lib/pairing.h | 1 + lib/raop.c | 16 ++++++--- lib/raop_handlers.h | 74 ++++++++++++++++++++++++++++++------------ uxplay.cpp | 3 ++ 9 files changed, 178 insertions(+), 45 deletions(-) diff --git a/lib/crypto.c b/lib/crypto.c index e41f190..dc140e4 100644 --- a/lib/crypto.c +++ b/lib/crypto.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -263,7 +264,6 @@ void x25519_derive_secret(unsigned char secret[X25519_KEY_SIZE], const x25519_ke // ED25519 - struct ed25519_key_s { EVP_PKEY *pkey; unsigned char ed_secret[ED25519_KEY_SIZE]; @@ -497,3 +497,7 @@ void sha_destroy(sha_ctx_t *ctx) { free(ctx); } } + +int get_random_bytes(unsigned char *buf, int num) { + return RAND_bytes(buf, num); +} diff --git a/lib/dnssd.c b/lib/dnssd.c index 4f0e35e..fdeb03e 100644 --- a/lib/dnssd.c +++ b/lib/dnssd.c @@ -145,15 +145,22 @@ struct dnssd_s { char *hw_addr; int hw_addr_len; + + uint32_t features1; + uint32_t features2; + + unsigned char require_pw; }; dnssd_t * -dnssd_init(const char* name, int name_len, const char* hw_addr, int hw_addr_len, int *error) +dnssd_init(const char* name, int name_len, const char* hw_addr, int hw_addr_len, int *error, int require_pw) { dnssd_t *dnssd; - + char *end; + unsigned long features; + if (error) *error = DNSSD_ERROR_NOERROR; dnssd = calloc(1, sizeof(dnssd_t)); @@ -162,6 +169,24 @@ dnssd_init(const char* name, int name_len, const char* hw_addr, int hw_addr_len, return NULL; } + dnssd->require_pw = (unsigned char) require_pw; + + features = strtoul(FEATURES_1, &end, 16); + if (!end || (features & 0xFFFFFFFF) != features) { + free (dnssd); + if (error) *error = DNSSD_ERROR_BADFEATURES; + return NULL; + } + dnssd->features1 = (uint32_t) features; + + features = strtoul(FEATURES_2, &end, 16); + if (!end || (features & 0xFFFFFFFF) != features) { + free (dnssd); + if (error) *error = DNSSD_ERROR_BADFEATURES; + return NULL; + } + dnssd->features2 = (uint32_t) features; + #ifdef WIN32 dnssd->module = LoadLibraryA("dnssd.dll"); if (!dnssd->module) { @@ -259,20 +284,27 @@ dnssd_register_raop(dnssd_t *dnssd, unsigned short port) { char servname[MAX_SERVNAME]; DNSServiceErrorType retval; + char features[22]; assert(dnssd); + snprintf(features, sizeof(features), "0x%X,0x%X", dnssd->features1, dnssd->features2); + dnssd->TXTRecordCreate(&dnssd->raop_record, 0, NULL); dnssd->TXTRecordSetValue(&dnssd->raop_record, "ch", strlen(RAOP_CH), RAOP_CH); dnssd->TXTRecordSetValue(&dnssd->raop_record, "cn", strlen(RAOP_CN), RAOP_CN); dnssd->TXTRecordSetValue(&dnssd->raop_record, "da", strlen(RAOP_DA), RAOP_DA); dnssd->TXTRecordSetValue(&dnssd->raop_record, "et", strlen(RAOP_ET), RAOP_ET); dnssd->TXTRecordSetValue(&dnssd->raop_record, "vv", strlen(RAOP_VV), RAOP_VV); - dnssd->TXTRecordSetValue(&dnssd->raop_record, "ft", strlen(RAOP_FT), RAOP_FT); + dnssd->TXTRecordSetValue(&dnssd->raop_record, "ft", strlen(features), features); dnssd->TXTRecordSetValue(&dnssd->raop_record, "am", strlen(GLOBAL_MODEL), GLOBAL_MODEL); dnssd->TXTRecordSetValue(&dnssd->raop_record, "md", strlen(RAOP_MD), RAOP_MD); dnssd->TXTRecordSetValue(&dnssd->raop_record, "rhd", strlen(RAOP_RHD), RAOP_RHD); - dnssd->TXTRecordSetValue(&dnssd->raop_record, "pw", strlen("false"), "false"); + if (dnssd->require_pw) { + dnssd->TXTRecordSetValue(&dnssd->raop_record, "pw", strlen("true"), "true"); + } else { + dnssd->TXTRecordSetValue(&dnssd->raop_record, "pw", strlen("false"), "false"); + } dnssd->TXTRecordSetValue(&dnssd->raop_record, "sr", strlen(RAOP_SR), RAOP_SR); dnssd->TXTRecordSetValue(&dnssd->raop_record, "ss", strlen(RAOP_SS), RAOP_SS); dnssd->TXTRecordSetValue(&dnssd->raop_record, "sv", strlen(RAOP_SV), RAOP_SV); @@ -281,7 +313,7 @@ dnssd_register_raop(dnssd_t *dnssd, unsigned short port) dnssd->TXTRecordSetValue(&dnssd->raop_record, "sf", strlen(RAOP_SF), RAOP_SF); dnssd->TXTRecordSetValue(&dnssd->raop_record, "vs", strlen(RAOP_VS), RAOP_VS); dnssd->TXTRecordSetValue(&dnssd->raop_record, "vn", strlen(RAOP_VN), RAOP_VN); - dnssd->TXTRecordSetValue(&dnssd->raop_record, "pk", strlen(RAOP_PK), RAOP_PK); + dnssd->TXTRecordSetValue(&dnssd->raop_record, "pk", strlen(PK), PK); /* Convert hardware address to string */ if (utils_hwaddr_raop(servname, sizeof(servname), dnssd->hw_addr, dnssd->hw_addr_len) < 0) { @@ -315,9 +347,12 @@ dnssd_register_airplay(dnssd_t *dnssd, unsigned short port) { char device_id[3 * MAX_HWADDR_LEN]; DNSServiceErrorType retval; + char features[22]; assert(dnssd); + snprintf(features, sizeof(features), "0x%X,0x%X", dnssd->features1, dnssd->features2); + /* Convert hardware address to string */ if (utils_hwaddr_airplay(device_id, sizeof(device_id), dnssd->hw_addr, dnssd->hw_addr_len) < 0) { /* FIXME: handle better */ @@ -327,10 +362,15 @@ dnssd_register_airplay(dnssd_t *dnssd, unsigned short port) dnssd->TXTRecordCreate(&dnssd->airplay_record, 0, NULL); dnssd->TXTRecordSetValue(&dnssd->airplay_record, "deviceid", strlen(device_id), device_id); - dnssd->TXTRecordSetValue(&dnssd->airplay_record, "features", strlen(AIRPLAY_FEATURES), AIRPLAY_FEATURES); + dnssd->TXTRecordSetValue(&dnssd->airplay_record, "features", strlen(features), features); dnssd->TXTRecordSetValue(&dnssd->airplay_record, "flags", strlen(AIRPLAY_FLAGS), AIRPLAY_FLAGS); dnssd->TXTRecordSetValue(&dnssd->airplay_record, "model", strlen(GLOBAL_MODEL), GLOBAL_MODEL); - dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pk", strlen(AIRPLAY_PK), AIRPLAY_PK); + dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pk", strlen(PK), PK); + if (dnssd->require_pw) { + dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pw", strlen("true"), "true"); + } else { + dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pw", strlen("false"), "false"); + } dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pi", strlen(AIRPLAY_PI), AIRPLAY_PI); dnssd->TXTRecordSetValue(&dnssd->airplay_record, "srcvers", strlen(AIRPLAY_SRCVERS), AIRPLAY_SRCVERS); dnssd->TXTRecordSetValue(&dnssd->airplay_record, "vv", strlen(AIRPLAY_VV), AIRPLAY_VV); @@ -409,3 +449,28 @@ dnssd_unregister_airplay(dnssd_t *dnssd) free(dnssd->hw_addr); } } + +uint64_t dnssd_get_airplay_features(dnssd_t *dnssd) { + uint64_t features = ((uint64_t) dnssd->features2) << 32; + features += (uint64_t) dnssd->features1; + return features; +} + +void dnssd_set_airplay_features(dnssd_t *dnssd, int bit, int val) { + uint32_t mask; + uint32_t *features; + if (bit < 0 || bit > 63) return; + if (val < 0 || val > 1) return; + if (bit >= 32) { + mask = 0x1 << (bit - 32); + features = &(dnssd->features2); + } else { + mask = 0x1 << bit; + features = &(dnssd->features1); + } + if (val) { + *features = *features | mask; + } else { + *features = *features & ~mask; + } +} diff --git a/lib/dnssd.h b/lib/dnssd.h index 17cb5d7..1e3da32 100644 --- a/lib/dnssd.h +++ b/lib/dnssd.h @@ -14,6 +14,7 @@ #ifndef DNSSD_H #define DNSSD_H +#include #if defined(WIN32) && defined(DLL_EXPORT) # define DNSSD_API __declspec(dllexport) @@ -30,10 +31,11 @@ extern "C" { #define DNSSD_ERROR_OUTOFMEM 2 #define DNSSD_ERROR_LIBNOTFOUND 3 #define DNSSD_ERROR_PROCNOTFOUND 4 +#define DNSSD_ERROR_BADFEATURES 5 typedef struct dnssd_s dnssd_t; -DNSSD_API dnssd_t *dnssd_init(const char *name, int name_len, const char *hw_addr, int hw_addr_len, int *error); + DNSSD_API dnssd_t *dnssd_init(const char *name, int name_len, const char *hw_addr, int hw_addr_len, int *error, int require_pw); DNSSD_API int dnssd_register_raop(dnssd_t *dnssd, unsigned short port); DNSSD_API int dnssd_register_airplay(dnssd_t *dnssd, unsigned short port); @@ -44,7 +46,9 @@ DNSSD_API void dnssd_unregister_airplay(dnssd_t *dnssd); DNSSD_API const char *dnssd_get_airplay_txt(dnssd_t *dnssd, int *length); DNSSD_API const char *dnssd_get_name(dnssd_t *dnssd, int *length); DNSSD_API const char *dnssd_get_hw_addr(dnssd_t *dnssd, int *length); - +DNSSD_API void dnssd_set_airplay_features(dnssd_t *dnssd, int bit, int val); +DNSSD_API uint64_t dnssd_get_airplay_features(dnssd_t *dnssd); + DNSSD_API void dnssd_destroy(dnssd_t *dnssd); #ifdef __cplusplus diff --git a/lib/dnssdint.h b/lib/dnssdint.h index dfb475a..338b5b8 100644 --- a/lib/dnssdint.h +++ b/lib/dnssdint.h @@ -19,15 +19,17 @@ #define DNSSDINT_H #include "global.h" + +#define PK "b07727d6f6cd6e08b58ede525ec3cdeaa252ad9f683feb212ef8a205246554e7" + #define RAOP_TXTVERS "1" #define RAOP_CH "2" /* Audio channels: 2 */ #define RAOP_CN "0,1,2,3" /* Audio codec: PCM, ALAC, AAC, AAC ELD */ #define RAOP_ET "0,3,5" /* Encryption type: None, FairPlay, FairPlay SAPv2.5 */ #define RAOP_VV "2" -//#define FEATURES_1 "0x5A7FFEE6" /* first 32 bits of features, with bit 27 ("supports legacy pairing") ON */ -#define FEATURES_1 "0x527FFEE6" /* first 32 bits of features, with bit 27 ("supports legacy pairing") OFF */ -#define FEATURES_2 "0x0" /* second 32 bits of features */ -#define RAOP_FT FEATURES_1 "," FEATURES_2 +#define FEATURES_1 "0x5A7FFEE6" /* first 32 bits of features, with bit 27 ("supports legacy pairing") ON */ +//#define FEATURES_1 "0x527FFEE6" /* first 32 bits of features, with bit 27 ("supports legacy pairing") OFF */ +#define FEATURES_2 "0x0" /* second 32 bits of features */ #define RAOP_RHD "5.6.0.0" #define RAOP_SF "0x4" #define RAOP_SV "false" @@ -38,16 +40,10 @@ #define RAOP_TP "UDP" /* Transport protocol. Possible values: UDP or TCP or TCP,UDP */ #define RAOP_MD "0,1,2" /* Metadata: text, artwork, progress */ #define RAOP_VN "65537" -#define RAOP_PK "b07727d6f6cd6e08b58ede525ec3cdeaa252ad9f683feb212ef8a205246554e7" -/* use same features for RAOP and AIRPLAY: is this correct? */ -#define AIRPLAY_FEATURES_1 FEATURES_1 -#define AIRPLAY_FEATURES_2 FEATURES_2 -#define AIRPLAY_FEATURES AIRPLAY_FEATURES_1 "," AIRPLAY_FEATURES_2 #define AIRPLAY_SRCVERS GLOBAL_VERSION /*defined in global.h */ #define AIRPLAY_FLAGS "0x4" #define AIRPLAY_VV "2" -#define AIRPLAY_PK "b07727d6f6cd6e08b58ede525ec3cdeaa252ad9f683feb212ef8a205246554e7" #define AIRPLAY_PI "2e388006-13ba-4041-9a67-25dd4a43d536" #endif diff --git a/lib/pairing.c b/lib/pairing.c index 5a0a3b3..848a7bc 100644 --- a/lib/pairing.c +++ b/lib/pairing.c @@ -269,3 +269,23 @@ pairing_destroy(pairing_t *pairing) free(pairing); } } + +int +random_pin() { + unsigned char random_bytes[2] = { 0 }; + unsigned short random_short = 0; + int ret; + /* create a random unsigned short in range 1-9999 */ + while (!random_short) { + if ((ret = get_random_bytes(random_bytes, sizeof(random_bytes)) < 1)) { + return -1; + } + memcpy(&random_short, random_bytes, sizeof(random_bytes)); + random_short = random_short % 10000; + } + return (int) random_short; +} + + + + diff --git a/lib/pairing.h b/lib/pairing.h index e57a9c8..66005ec 100644 --- a/lib/pairing.h +++ b/lib/pairing.h @@ -32,6 +32,7 @@ int pairing_session_check_handshake_status(pairing_session_t *session); int pairing_session_handshake(pairing_session_t *session, const unsigned char ecdh_key[X25519_KEY_SIZE], const unsigned char ed_key[ED25519_KEY_SIZE]); int pairing_session_get_public_key(pairing_session_t *session, unsigned char ecdh_key[X25519_KEY_SIZE]); +int random_pin(); int pairing_session_get_signature(pairing_session_t *session, unsigned char signature[PAIRING_SIG_SIZE]); int pairing_session_finish(pairing_session_t *session, const unsigned char signature[PAIRING_SIG_SIZE]); void pairing_session_destroy(pairing_session_t *session); diff --git a/lib/raop.c b/lib/raop.c index a88f1eb..d3aa2ef 100644 --- a/lib/raop.c +++ b/lib/raop.c @@ -65,6 +65,9 @@ struct raop_s { int audio_delay_micros; int max_ntp_timeouts; + + /* for temporary storage of pin during pair-pin start */ + unsigned short pin; }; struct raop_conn_s { @@ -215,11 +218,9 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) { if (!strcmp(method, "GET") && !strcmp(url, "/info")) { handler = &raop_handler_info; } else if (!strcmp(method, "POST") && !strcmp(url, "/pair-pin-start")) { - logger_log(conn->raop->logger, LOGGER_ERR, "*** ERROR: Unsupported client request %s with URL %s", method, url); - logger_log(conn->raop->logger, LOGGER_INFO, "*** AirPlay client has requested PIN as implemented on AppleTV,"); - logger_log(conn->raop->logger, LOGGER_INFO, "*** but this implementation does not require a PIN and cannot supply one."); - logger_log(conn->raop->logger, LOGGER_INFO, "*** This client behavior may have been required by mobile device management (MDM)"); - logger_log(conn->raop->logger, LOGGER_INFO, "*** (such as Apple Configurator or a third-party MDM tool)."); + handler = &raop_handler_pairpinstart; + } else if (!strcmp(method, "POST") && !strcmp(url, "/pair-setup-pin")) { + handler = &raop_handler_pairsetup_pin; } else if (!strcmp(method, "POST") && !strcmp(url, "/pair-setup")) { handler = &raop_handler_pairsetup; } else if (!strcmp(method, "POST") && !strcmp(url, "/pair-verify")) { @@ -422,6 +423,8 @@ raop_init(int max_clients, raop_callbacks_t *callbacks) { /* Initialize the logger */ raop->logger = logger_init(); + + /* create a new public key for pairing */ pairing = pairing_init_generate(); if (!pairing) { free(raop); @@ -461,6 +464,9 @@ raop_init(int max_clients, raop_callbacks_t *callbacks) { raop->maxFPS = 30; raop->overscanned = 0; + /* initialise stored pin */ + raop->pin = 0; + /* initialize switch for display of client's streaming data records */ raop->clientFPSdata = 0; diff --git a/lib/raop_handlers.h b/lib/raop_handlers.h index b1ca1cc..b102019 100644 --- a/lib/raop_handlers.h +++ b/lib/raop_handlers.h @@ -50,16 +50,14 @@ raop_handler_info(raop_conn_t *conn, utils_hwaddr_airplay(hw_addr, 3 * hw_addr_raw_len, hw_addr_raw, hw_addr_raw_len); int pk_len = 0; - char *pk = utils_parse_hex(AIRPLAY_PK, strlen(AIRPLAY_PK), &pk_len); - - uint64_t features = ((uint64_t) strtoul(AIRPLAY_FEATURES_2, NULL, 16)) << 32; - features += (uint64_t) strtoul(AIRPLAY_FEATURES_1, NULL, 16); + char *pk = utils_parse_hex(PK, strlen(PK), &pk_len); plist_t r_node = plist_new_dict(); plist_t txt_airplay_node = plist_new_data(airplay_txt, airplay_txt_len); plist_dict_set_item(r_node, "txtAirPlay", txt_airplay_node); + uint64_t features = dnssd_get_airplay_features(conn->raop->dnssd); plist_t features_node = plist_new_uint(features); plist_dict_set_item(r_node, "features", features_node); @@ -94,44 +92,44 @@ raop_handler_info(raop_conn_t *conn, plist_t status_flags_node = plist_new_uint(68); plist_dict_set_item(r_node, "statusFlags", status_flags_node); + plist_t keep_alive_low_power_node = plist_new_uint(1); + plist_dict_set_item(r_node, "keepAliveLowPower", keep_alive_low_power_node); + plist_t source_version_node = plist_new_string(GLOBAL_VERSION); plist_dict_set_item(r_node, "sourceVersion", source_version_node); plist_t pk_node = plist_new_data(pk, pk_len); plist_dict_set_item(r_node, "pk", pk_node); + plist_t keep_alive_send_stats_as_body_node = plist_new_uint(1); + plist_dict_set_item(r_node, "keepAliveSendStatsAsBody", keep_alive_send_stats_as_body_node); + plist_t device_id_node = plist_new_string(hw_addr); plist_dict_set_item(r_node, "deviceID", device_id_node); plist_t audio_latencies_node = plist_new_array(); plist_t audio_latencies_0_node = plist_new_dict(); - plist_t audio_latencies_0_audio_type_node = plist_new_string("default"); - plist_t audio_latencies_0_input_latency_micros_node = plist_new_uint(0); - plist_t audio_latencies_0_output_latency_micros_node = plist_new_uint(0); + plist_t audio_latencies_0_output_latency_micros_node = plist_new_bool(0); plist_t audio_latencies_0_type_node = plist_new_uint(100); - plist_dict_set_item(audio_latencies_0_node, "audioType", audio_latencies_0_audio_type_node); - plist_dict_set_item(audio_latencies_0_node, "inputLatencyMicros", audio_latencies_0_input_latency_micros_node); + plist_t audio_latencies_0_audio_type_node = plist_new_string("default"); + plist_t audio_latencies_0_input_latency_micros_node = plist_new_bool(0); plist_dict_set_item(audio_latencies_0_node, "outputLatencyMicros", audio_latencies_0_output_latency_micros_node); plist_dict_set_item(audio_latencies_0_node, "type", audio_latencies_0_type_node); + plist_dict_set_item(audio_latencies_0_node, "audioType", audio_latencies_0_audio_type_node); + plist_dict_set_item(audio_latencies_0_node, "inputLatencyMicros", audio_latencies_0_input_latency_micros_node); plist_array_append_item(audio_latencies_node, audio_latencies_0_node); plist_t audio_latencies_1_node = plist_new_dict(); - plist_t audio_latencies_1_audio_type_node = plist_new_string("default"); - plist_t audio_latencies_1_input_latency_micros_node = plist_new_uint(0); - plist_t audio_latencies_1_output_latency_micros_node = plist_new_uint(0); + plist_t audio_latencies_1_output_latency_micros_node = plist_new_bool(0); plist_t audio_latencies_1_type_node = plist_new_uint(101); - plist_dict_set_item(audio_latencies_1_node, "audioType", audio_latencies_1_audio_type_node); - plist_dict_set_item(audio_latencies_1_node, "inputLatencyMicros", audio_latencies_1_input_latency_micros_node); + plist_t audio_latencies_1_audio_type_node = plist_new_string("default"); + plist_t audio_latencies_1_input_latency_micros_node = plist_new_bool(0); plist_dict_set_item(audio_latencies_1_node, "outputLatencyMicros", audio_latencies_1_output_latency_micros_node); plist_dict_set_item(audio_latencies_1_node, "type", audio_latencies_1_type_node); + plist_dict_set_item(audio_latencies_1_node, "audioType", audio_latencies_1_audio_type_node); + plist_dict_set_item(audio_latencies_1_node, "inputLatencyMicros", audio_latencies_1_input_latency_micros_node); plist_array_append_item(audio_latencies_node, audio_latencies_1_node); plist_dict_set_item(r_node, "audioLatencies", audio_latencies_node); - plist_t keep_alive_low_power_node = plist_new_bool(1); - plist_dict_set_item(r_node, "keepAliveLowPower", keep_alive_low_power_node); - - plist_t keep_alive_send_stats_as_body_node = plist_new_bool(1); - plist_dict_set_item(r_node, "keepAliveSendStatsAsBody", keep_alive_send_stats_as_body_node); - plist_t model_node = plist_new_string(GLOBAL_MODEL); plist_dict_set_item(r_node, "model", model_node); @@ -152,6 +150,7 @@ raop_handler_info(raop_conn_t *conn, plist_t displays_0_max_fps_node = plist_new_uint(conn->raop->maxFPS); plist_t displays_0_overscanned_node = plist_new_bool(conn->raop->overscanned); plist_t displays_0_features = plist_new_uint(14); + plist_dict_set_item(displays_0_node, "uuid", displays_0_uuid_node); plist_dict_set_item(displays_0_node, "widthPhysical", displays_0_width_physical_node); plist_dict_set_item(displays_0_node, "heightPhysical", displays_0_height_physical_node); @@ -174,6 +173,41 @@ raop_handler_info(raop_conn_t *conn, free(hw_addr); } +static void +raop_handler_pairpinstart(raop_conn_t *conn, + http_request_t *request, http_response_t *response, + char **response_data, int *response_datalen) { + logger_log(conn->raop->logger, LOGGER_INFO, "client sent PAIR-PIN-START request"); + int pin_4 = random_pin(); + conn->raop->pin = (unsigned short) pin_4; + if (pin_4 < 0) { + logger_log(conn->raop->logger, LOGGER_ERR, "Failed to generate random pin"); + } else { + char pin[6]; + snprintf(pin, 5, "%04u", pin_4); + if (conn->raop->callbacks.display_pin) { + conn->raop->callbacks.display_pin(conn->raop->callbacks.cls, pin); + } + logger_log(conn->raop->logger, LOGGER_INFO, "*** CLIENT MUST NOW ENTER PIN = \"%s\" AS AIRPLAY PASSWORD", pin); + } + *response_data = NULL; + response_datalen = 0; + return; +} + +static void +raop_handler_pairsetup_pin(raop_conn_t *conn, + http_request_t *request, http_response_t *response, + char **response_data, int *response_datalen) { + + /* does nothing yet */ + + + *response_data = NULL; + response_datalen = 0; + return; +} + static void raop_handler_pairsetup(raop_conn_t *conn, http_request_t *request, http_response_t *response, diff --git a/uxplay.cpp b/uxplay.cpp index 07340f9..2a8c10d 100644 --- a/uxplay.cpp +++ b/uxplay.cpp @@ -126,6 +126,8 @@ static uint64_t remote_clock_offset = 0; static std::vector allowed_clients; static std::vector blocked_clients; static bool restrict_clients; +static bool setup_legacy_pairing = true; +static bool require_password = false; /* logging */ @@ -607,6 +609,7 @@ static void print_info (char *name) { printf("Options:\n"); printf("-n name Specify the network name of the AirPlay server\n"); printf("-nh Do not add \"@hostname\" at the end of AirPlay server name\n"); + printf("-pair Support Airplay (legacy) client-pairing (default: not used)\n"); printf("-vsync [x]Mirror mode: sync audio to video using timestamps (default)\n"); printf(" x is optional audio delay: millisecs, decimal, can be neg.\n"); printf("-vsync no Switch off audio/(server)video timestamp synchronization \n");