diff --git a/lib/raop.c b/lib/raop.c index d3aa2ef..a6a11d8 100644 --- a/lib/raop.c +++ b/lib/raop.c @@ -535,7 +535,9 @@ int raop_set_plist(raop_t *raop, const char *plist_item, const int value) { raop->audio_delay_micros = value; } if (raop->audio_delay_micros != value) retval = 1; - } else { + } else if (strcmp(plist_item, "pin") == 0) { + raop->pin = value; + } else { retval = -1; } return retval; diff --git a/lib/raop_handlers.h b/lib/raop_handlers.h index 8dd1a02..d245c4b 100644 --- a/lib/raop_handlers.h +++ b/lib/raop_handlers.h @@ -178,18 +178,23 @@ 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"); + int pin_4; + if (conn->raop->pin > 9999) { + pin_4 = conn->raop->pin % 10000; } 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); + pin_4 = random_pin(); + if (pin_4 < 0) { + logger_log(conn->raop->logger, LOGGER_ERR, "Failed to generate random pin"); + } else { + conn->raop->pin = (unsigned short) pin_4 % 10000; } - logger_log(conn->raop->logger, LOGGER_INFO, "*** CLIENT MUST NOW ENTER PIN = \"%s\" AS AIRPLAY PASSWORD", pin); } + 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; @@ -248,8 +253,10 @@ raop_handler_pairsetup_pin(raop_conn_t *conn, free (method); plist_get_string_val(req_user_node, &user); logger_log(conn->raop->logger, LOGGER_INFO, "pair-setup-pin: device_id = %s", user); - snprintf(pin, 6, "%04u", conn->raop->pin); - conn->raop->pin = 0; + snprintf(pin, 6, "%04u", conn->raop->pin % 10000); + if (conn->raop->pin < 10000) { + conn->raop->pin = 0; + } int ret = srp_new_user(conn->pairing, conn->raop->pairing, (const char *) user, (const char *) pin, &salt, &len_salt, &pk, &len_pk); free(user); diff --git a/uxplay.1 b/uxplay.1 index 79f8832..3171eec 100644 --- a/uxplay.1 +++ b/uxplay.1 @@ -1,11 +1,11 @@ -.TH UXPLAY "1" "September 2023" "1.66" "User Commands" +.TH UXPLAY "1" "November 2023" "1.67" "User Commands" .SH NAME uxplay \- start AirPlay server .SH SYNOPSIS .B uxplay [\fI\,-n name\/\fR] [\fI\,-s wxh\/\fR] [\fI\,-p \/\fR[\fI\,n\/\fR]] [more \fI OPTIONS \/\fR ...] .SH DESCRIPTION -UxPlay 1.66: An open\-source AirPlay mirroring (+ audio streaming) server: +UxPlay 1.67: An open\-source AirPlay mirroring (+ audio streaming) server: .SH OPTIONS .TP .B @@ -13,6 +13,10 @@ UxPlay 1.66: An open\-source AirPlay mirroring (+ audio streaming) server: .TP \fB\-nh\fR Do \fBNOT\fR append "@\fIhostname\fR" at end of AirPlay server name .TP +\fB\-pin\fI[nnnn]\fRUse a 4-digit pin code to control client access (default: no) +.IP + [optionally choose fixed pin]; default pin varies randomly. +.TP \fB\-vsync\fI[x]\fR Mirror mode: sync audio to video using timestamps (default) .IP \fIx\fR is optional audio delay: millisecs, decimal, can be neg. diff --git a/uxplay.cpp b/uxplay.cpp index 2a8c10d..4504b1e 100644 --- a/uxplay.cpp +++ b/uxplay.cpp @@ -60,7 +60,7 @@ #include "renderers/video_renderer.h" #include "renderers/audio_renderer.h" -#define VERSION "1.66" +#define VERSION "1.67" #define SECOND_IN_USECS 1000000 #define SECOND_IN_NSECS 1000000000UL @@ -126,8 +126,9 @@ 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 setup_legacy_pairing = false; static bool require_password = false; +static unsigned short pin = 0; /* logging */ @@ -609,7 +610,8 @@ 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("-pin[xxxx]Use a 4=digit pin code to control client access (default: no)\n"); + printf(" [optionally choose fixed pin]; default pin varies randomly\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"); @@ -1072,10 +1074,18 @@ static void parse_arguments (int argc, char *argv[]) { fprintf(stderr, "invalid argument -al %s: must be a decimal time offset in seconds, range [0,10]\n" "(like 5 or 4.8, which will be converted to a whole number of microseconds)\n", argv[i]); exit(1); - } else if (arg == "-pair") { + } else if (arg == "-pin") { setup_legacy_pairing = true; - require_password = true; /* for testing purposed only ??? */ - } else { + require_password = true; + if (option_has_value(i, argc, arg, argv[i+1])) { + unsigned int n = 9999; + if (!get_value(argv[++i], &n)) { + fprintf(stderr, "invalid \"-pin %s\"; -pin nnnn : max nnnn=9999, (4 digits)\n", argv[i]); + exit(1); + } + pin = n + 10000; + } + } else { fprintf(stderr, "unknown option %s, stopping (for help use option \"-h\")\n",argv[i]); exit(1); } @@ -1594,10 +1604,11 @@ int start_raop_server (unsigned short display[5], unsigned short tcp[3], unsigne if (display[2]) raop_set_plist(raop, "refreshRate", (int) display[2]); if (display[3]) raop_set_plist(raop, "maxFPS", (int) display[3]); if (display[4]) raop_set_plist(raop, "overscanned", (int) display[4]); - + if (show_client_FPS_data) raop_set_plist(raop, "clientFPSdata", 1); raop_set_plist(raop, "max_ntp_timeouts", max_ntp_timeouts); if (audiodelay >= 0) raop_set_plist(raop, "audio_delay_micros", audiodelay); + if (pin) raop_set_plist(raop, "pin", (int) pin); /* network port selection (ports listed as "0" will be dynamically assigned) */ raop_set_tcp_ports(raop, tcp);