raop.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969
  1. /*
  2. *
  3. * (c) Philippe 2019, philippe_44@outlook.com
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. #include <stdio.h>
  20. #include "platform.h"
  21. #ifdef WIN32
  22. #include <openssl/err.h>
  23. #include <openssl/rand.h>
  24. #include <openssl/rsa.h>
  25. #include <openssl/pem.h>
  26. #include <openssl/engine.h>
  27. #include "mdns.h"
  28. #include "mdnsd.h"
  29. #include "mdnssd-itf.h"
  30. #else
  31. #include "esp_pthread.h"
  32. #include "mdns.h"
  33. #include "mbedtls/version.h"
  34. #include <mbedtls/x509.h>
  35. #endif
  36. #include "util.h"
  37. #include "raop.h"
  38. #include "rtp.h"
  39. #include "dmap_parser.h"
  40. #include "log_util.h"
  41. #define RTSP_STACK_SIZE (8*1024)
  42. #define SEARCH_STACK_SIZE (2*1048)
  43. typedef struct raop_ctx_s {
  44. #ifdef WIN32
  45. struct mdns_service *svc;
  46. struct mdnsd *svr;
  47. #endif
  48. struct in_addr host; // IP of bridge
  49. short unsigned port; // RTSP port for AirPlay
  50. int sock; // socket of the above
  51. struct in_addr peer; // IP of the iDevice (airplay sender)
  52. bool running;
  53. #ifdef WIN32
  54. pthread_t thread, search_thread;
  55. #else
  56. TaskHandle_t thread, search_thread, joiner;
  57. StaticTask_t *xTaskBuffer;
  58. StackType_t xStack[RTSP_STACK_SIZE] __attribute__ ((aligned (4)));
  59. #endif
  60. unsigned char mac[6];
  61. int latency;
  62. struct {
  63. char *aesiv, *aeskey;
  64. char *fmtp;
  65. } rtsp;
  66. struct rtp_s *rtp;
  67. raop_cmd_cb_t cmd_cb;
  68. raop_data_cb_t data_cb;
  69. struct {
  70. char DACPid[32], id[32];
  71. struct in_addr host;
  72. u16_t port;
  73. #ifdef WIN32
  74. struct mDNShandle_s *handle;
  75. #else
  76. bool running;
  77. TaskHandle_t thread, joiner;
  78. StaticTask_t *xTaskBuffer;
  79. StackType_t xStack[SEARCH_STACK_SIZE] __attribute__ ((aligned (4)));;
  80. #endif
  81. } active_remote;
  82. void *owner;
  83. } raop_ctx_t;
  84. extern struct mdnsd* glmDNSServer;
  85. extern log_level raop_loglevel;
  86. static log_level *loglevel = &raop_loglevel;
  87. static void* rtsp_thread(void *arg);
  88. static bool handle_rtsp(raop_ctx_t *ctx, int sock);
  89. static char* rsa_apply(unsigned char *input, int inlen, int *outlen, int mode);
  90. static int base64_pad(char *src, char **padded);
  91. static int base64_encode(const void *data, int size, char **str);
  92. static int base64_decode(const char *str, void *data);
  93. static void* search_remote(void *args);
  94. extern char private_key[];
  95. enum { RSA_MODE_KEY, RSA_MODE_AUTH };
  96. static void on_dmap_string(void *ctx, const char *code, const char *name, const char *buf, size_t len);
  97. /*----------------------------------------------------------------------------*/
  98. struct raop_ctx_s *raop_create(struct in_addr host, char *name,
  99. unsigned char mac[6], int latency,
  100. raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb) {
  101. struct raop_ctx_s *ctx = malloc(sizeof(struct raop_ctx_s));
  102. struct sockaddr_in addr;
  103. char id[64];
  104. #ifdef WIN32
  105. socklen_t nlen = sizeof(struct sockaddr);
  106. char *txt[] = { "am=airesp32", "tp=UDP", "sm=false", "sv=false", "ek=1",
  107. "et=0,1", "md=0,1,2", "cn=0,1", "ch=2",
  108. "ss=16", "sr=44100", "vn=3", "txtvers=1",
  109. NULL };
  110. #else
  111. mdns_txt_item_t txt[] = {
  112. {"am", "airesp32"},
  113. {"tp", "UDP"},
  114. {"sm","false"},
  115. {"sv","false"},
  116. {"ek","1"},
  117. {"et","0,1"},
  118. {"md","0,1,2"},
  119. {"cn","0,1"},
  120. {"ch","2"},
  121. {"ss","16"},
  122. {"sr","44100"},
  123. {"vn","3"},
  124. {"txtvers","1"},
  125. };
  126. #endif
  127. if (!ctx) return NULL;
  128. // make sure we have a clean context
  129. memset(ctx, 0, sizeof(raop_ctx_t));
  130. #ifdef WIN32
  131. ctx->svr = glmDNSServer;
  132. #endif
  133. ctx->host = host;
  134. ctx->sock = socket(AF_INET, SOCK_STREAM, 0);
  135. ctx->cmd_cb = cmd_cb;
  136. ctx->data_cb = data_cb;
  137. ctx->latency = min(latency, 88200);
  138. if (ctx->sock == -1) {
  139. LOG_ERROR("Cannot create listening socket", NULL);
  140. free(ctx);
  141. return NULL;
  142. }
  143. memset(&addr, 0, sizeof(addr));
  144. addr.sin_addr.s_addr = host.s_addr;
  145. addr.sin_family = AF_INET;
  146. #ifdef WIN32
  147. ctx->port = 0;
  148. addr.sin_port = htons(ctx->port);
  149. #else
  150. ctx->port = 5000;
  151. addr.sin_port = htons(ctx->port);
  152. #endif
  153. if (bind(ctx->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0 || listen(ctx->sock, 1)) {
  154. LOG_ERROR("Cannot bind or listen RTSP listener: %s", strerror(errno));
  155. free(ctx);
  156. closesocket(ctx->sock);
  157. return NULL;
  158. }
  159. #ifdef WIN32
  160. getsockname(ctx->sock, (struct sockaddr *) &addr, &nlen);
  161. ctx->port = ntohs(addr.sin_port);
  162. #endif
  163. ctx->running = true;
  164. memcpy(ctx->mac, mac, 6);
  165. snprintf(id, 64, "%02X%02X%02X%02X%02X%02X@%s", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], name);
  166. #ifdef WIN32
  167. // seems that Windows snprintf does not add NULL char if actual size > max
  168. id[63] = '\0';
  169. ctx->svc = mdnsd_register_svc(ctx->svr, id, "_raop._tcp.local", ctx->port, NULL, (const char**) txt);
  170. pthread_create(&ctx->thread, NULL, &rtsp_thread, ctx);
  171. #else
  172. LOG_INFO("starting mDNS with %s", id);
  173. ESP_ERROR_CHECK( mdns_service_add(id, "_raop", "_tcp", ctx->port, txt, sizeof(txt) / sizeof(mdns_txt_item_t)) );
  174. ctx->xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
  175. ctx->thread = xTaskCreateStatic( (TaskFunction_t) rtsp_thread, "RTSP_thread", RTSP_STACK_SIZE, ctx, ESP_TASK_PRIO_MIN + 1, ctx->xStack, ctx->xTaskBuffer);
  176. #endif
  177. return ctx;
  178. }
  179. /*----------------------------------------------------------------------------*/
  180. void raop_delete(struct raop_ctx_s *ctx) {
  181. #ifdef WIN32
  182. int sock;
  183. struct sockaddr addr;
  184. socklen_t nlen = sizeof(struct sockaddr);
  185. #endif
  186. if (!ctx) return;
  187. #ifdef WIN32
  188. ctx->running = false;
  189. // wake-up thread by connecting socket, needed for freeBSD
  190. sock = socket(AF_INET, SOCK_STREAM, 0);
  191. getsockname(ctx->sock, (struct sockaddr *) &addr, &nlen);
  192. connect(sock, (struct sockaddr*) &addr, sizeof(addr));
  193. closesocket(sock);
  194. pthread_join(ctx->thread, NULL);
  195. rtp_end(ctx->rtp);
  196. shutdown(ctx->sock, SD_BOTH);
  197. closesocket(ctx->sock);
  198. // terminate search, but do not reclaim memory of pthread if never launched
  199. if (ctx->active_remote.handle) {
  200. close_mDNS(ctx->active_remote.handle);
  201. pthread_join(ctx->search_thread, NULL);
  202. }
  203. // stop broadcasting devices
  204. mdns_service_remove(ctx->svr, ctx->svc);
  205. mdnsd_stop(ctx->svr);
  206. #else
  207. // first stop the search task if any
  208. if (ctx->active_remote.running) {
  209. ctx->active_remote.joiner = xTaskGetCurrentTaskHandle();
  210. ctx->active_remote.running = false;
  211. vTaskResume(ctx->active_remote.thread);
  212. ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
  213. vTaskDelete(ctx->active_remote.thread);
  214. heap_caps_free(ctx->active_remote.xTaskBuffer);
  215. }
  216. // then the RTSP task
  217. ctx->joiner = xTaskGetCurrentTaskHandle();
  218. ctx->running = false;
  219. ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
  220. vTaskDelete(ctx->thread);
  221. heap_caps_free(ctx->xTaskBuffer);
  222. rtp_end(ctx->rtp);
  223. shutdown(ctx->sock, SHUT_RDWR);
  224. closesocket(ctx->sock);
  225. mdns_service_remove("_raop", "_tcp");
  226. #endif
  227. NFREE(ctx->rtsp.aeskey);
  228. NFREE(ctx->rtsp.aesiv);
  229. NFREE(ctx->rtsp.fmtp);
  230. free(ctx);
  231. }
  232. /*----------------------------------------------------------------------------*/
  233. void raop_cmd(struct raop_ctx_s *ctx, raop_event_t event, void *param) {
  234. struct sockaddr_in addr;
  235. int sock;
  236. char *command = NULL;
  237. // first notify the remote controller (if any)
  238. switch(event) {
  239. case RAOP_REW:
  240. command = strdup("beginrew");
  241. break;
  242. case RAOP_FWD:
  243. command = strdup("beginff");
  244. break;
  245. case RAOP_PREV:
  246. command = strdup("previtem");
  247. break;
  248. case RAOP_NEXT:
  249. command = strdup("nextitem");
  250. break;
  251. case RAOP_TOGGLE:
  252. command = strdup("playpause");
  253. break;
  254. case RAOP_PAUSE:
  255. command = strdup("pause");
  256. break;
  257. case RAOP_PLAY:
  258. command = strdup("play");
  259. break;
  260. case RAOP_RESUME:
  261. command = strdup("playresume");
  262. break;
  263. case RAOP_STOP:
  264. command = strdup("stop");
  265. break;
  266. case RAOP_VOLUME_UP:
  267. command = strdup("volumeup");
  268. break;
  269. case RAOP_VOLUME_DOWN:
  270. command = strdup("volumedown");
  271. break;
  272. case RAOP_VOLUME: {
  273. float Volume = *((float*) param);
  274. Volume = Volume ? (Volume - 1) * 30 : -144;
  275. asprintf(&command,"setproperty?dmcp.device-volume=%0.4lf", Volume);
  276. break;
  277. }
  278. default:
  279. break;
  280. }
  281. // no command to send to remote or no remote found yet
  282. if (!command || !ctx->active_remote.port) {
  283. NFREE(command);
  284. return;
  285. }
  286. sock = socket(AF_INET, SOCK_STREAM, 0);
  287. memset(&addr, 0, sizeof(addr));
  288. addr.sin_family = AF_INET;
  289. addr.sin_addr.s_addr = S_ADDR(ctx->active_remote.host);
  290. addr.sin_port = htons(ctx->active_remote.port);
  291. if (!connect(sock, (struct sockaddr*) &addr, sizeof(addr))) {
  292. char *method, *buf, resp[512] = "";
  293. int len;
  294. key_data_t headers[4] = { {NULL, NULL} };
  295. asprintf(&method, "GET /ctrl-int/1/%s HTTP/1.0", command);
  296. kd_add(headers, "Active-Remote", ctx->active_remote.id);
  297. kd_add(headers, "Connection", "close");
  298. buf = http_send(sock, method, headers);
  299. len = recv(sock, resp, 512, 0);
  300. if (len > 0) resp[len-1] = '\0';
  301. LOG_INFO("[%p]: sending airplay remote\n%s<== received ==>\n%s", ctx, buf, resp);
  302. NFREE(method);
  303. NFREE(buf);
  304. kd_free(headers);
  305. }
  306. free(command);
  307. closesocket(sock);
  308. }
  309. /*----------------------------------------------------------------------------*/
  310. static void *rtsp_thread(void *arg) {
  311. raop_ctx_t *ctx = (raop_ctx_t*) arg;
  312. int sock = -1;
  313. while (ctx->running) {
  314. fd_set rfds;
  315. struct timeval timeout = {0, 100*1000};
  316. int n;
  317. bool res = false;
  318. if (sock == -1) {
  319. struct sockaddr_in peer;
  320. socklen_t addrlen = sizeof(struct sockaddr_in);
  321. sock = accept(ctx->sock, (struct sockaddr*) &peer, &addrlen);
  322. ctx->peer.s_addr = peer.sin_addr.s_addr;
  323. if (sock != -1 && ctx->running) {
  324. LOG_INFO("got RTSP connection %u", sock);
  325. } else continue;
  326. }
  327. FD_ZERO(&rfds);
  328. FD_SET(sock, &rfds);
  329. n = select(sock + 1, &rfds, NULL, NULL, &timeout);
  330. if (!n) continue;
  331. if (n > 0) res = handle_rtsp(ctx, sock);
  332. if (n < 0 || !res) {
  333. closesocket(sock);
  334. LOG_INFO("RTSP close %u", sock);
  335. sock = -1;
  336. }
  337. }
  338. if (sock != -1) closesocket(sock);
  339. #ifndef WIN32
  340. xTaskNotifyGive(ctx->joiner);
  341. vTaskSuspend(NULL);
  342. #endif
  343. return NULL;
  344. }
  345. /*----------------------------------------------------------------------------*/
  346. static bool handle_rtsp(raop_ctx_t *ctx, int sock)
  347. {
  348. char *buf = NULL, *body = NULL, method[16] = "";
  349. key_data_t headers[16], resp[8] = { {NULL, NULL} };
  350. int len;
  351. bool success = true;
  352. if (!http_parse(sock, method, headers, &body, &len)) {
  353. NFREE(body);
  354. kd_free(headers);
  355. return false;
  356. }
  357. if (strcmp(method, "OPTIONS")) {
  358. LOG_INFO("[%p]: received %s", ctx, method);
  359. }
  360. if ((buf = kd_lookup(headers, "Apple-Challenge")) != NULL) {
  361. int n;
  362. char *buf_pad, *p, *data_b64 = NULL, data[32];
  363. LOG_INFO("[%p]: challenge %s", ctx, buf);
  364. // need to pad the base64 string as apple device don't
  365. base64_pad(buf, &buf_pad);
  366. p = data + min(base64_decode(buf_pad, data), 32-10);
  367. p = (char*) memcpy(p, &S_ADDR(ctx->host), 4) + 4;
  368. p = (char*) memcpy(p, ctx->mac, 6) + 6;
  369. memset(p, 0, 32 - (p - data));
  370. p = rsa_apply((unsigned char*) data, 32, &n, RSA_MODE_AUTH);
  371. n = base64_encode(p, n, &data_b64);
  372. // remove padding as well (seems to be optional now)
  373. for (n = strlen(data_b64) - 1; n > 0 && data_b64[n] == '='; data_b64[n--] = '\0');
  374. kd_add(resp, "Apple-Response", data_b64);
  375. NFREE(p);
  376. NFREE(buf_pad);
  377. NFREE(data_b64);
  378. }
  379. if (!strcmp(method, "OPTIONS")) {
  380. kd_add(resp, "Public", "ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER");
  381. } else if (!strcmp(method, "ANNOUNCE")) {
  382. char *padded, *p;
  383. NFREE(ctx->rtsp.aeskey);
  384. NFREE(ctx->rtsp.aesiv);
  385. NFREE(ctx->rtsp.fmtp);
  386. // LMS might has taken over the player, leaving us with a running RTP session (should not happen)
  387. if (ctx->rtp) {
  388. LOG_WARN("[%p]: closing unfinished RTP session", ctx);
  389. rtp_end(ctx->rtp);
  390. }
  391. // same, should not happen unless we have missed a teardown ...
  392. if (ctx->active_remote.running) {
  393. ctx->active_remote.joiner = xTaskGetCurrentTaskHandle();
  394. ctx->active_remote.running = false;
  395. vTaskResume(ctx->active_remote.thread);
  396. ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
  397. vTaskDelete(ctx->active_remote.thread);
  398. heap_caps_free(ctx->active_remote.xTaskBuffer);
  399. memset(&ctx->active_remote, 0, sizeof(ctx->active_remote));
  400. LOG_WARN("[%p]: closing unfinished mDNS search", ctx);
  401. }
  402. if ((p = strcasestr(body, "rsaaeskey")) != NULL) {
  403. unsigned char *aeskey;
  404. int len, outlen;
  405. p = strextract(p, ":", "\r\n");
  406. base64_pad(p, &padded);
  407. aeskey = malloc(strlen(padded));
  408. len = base64_decode(padded, aeskey);
  409. ctx->rtsp.aeskey = rsa_apply(aeskey, len, &outlen, RSA_MODE_KEY);
  410. NFREE(p);
  411. NFREE(aeskey);
  412. NFREE(padded);
  413. }
  414. if ((p = strcasestr(body, "aesiv")) != NULL) {
  415. p = strextract(p, ":", "\r\n");
  416. base64_pad(p, &padded);
  417. ctx->rtsp.aesiv = malloc(strlen(padded));
  418. base64_decode(padded, ctx->rtsp.aesiv);
  419. NFREE(p);
  420. NFREE(padded);
  421. }
  422. if ((p = strcasestr(body, "fmtp")) != NULL) {
  423. p = strextract(p, ":", "\r\n");
  424. ctx->rtsp.fmtp = strdup(p);
  425. NFREE(p);
  426. }
  427. // on announce, search remote
  428. if ((buf = kd_lookup(headers, "DACP-ID")) != NULL) strcpy(ctx->active_remote.DACPid, buf);
  429. if ((buf = kd_lookup(headers, "Active-Remote")) != NULL) strcpy(ctx->active_remote.id, buf);
  430. #ifdef WIN32
  431. ctx->active_remote.handle = init_mDNS(false, ctx->host);
  432. pthread_create(&ctx->search_thread, NULL, &search_remote, ctx);
  433. #else
  434. ctx->active_remote.running = true;
  435. ctx->active_remote.xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
  436. ctx->active_remote.thread = xTaskCreateStatic( (TaskFunction_t) search_remote, "search_remote", SEARCH_STACK_SIZE, ctx, ESP_TASK_PRIO_MIN + 1, ctx->active_remote.xStack, ctx->active_remote.xTaskBuffer);
  437. #endif
  438. } else if (!strcmp(method, "SETUP") && ((buf = kd_lookup(headers, "Transport")) != NULL)) {
  439. char *p;
  440. rtp_resp_t rtp = { 0 };
  441. short unsigned tport = 0, cport = 0;
  442. // we are about to stream, do something if needed
  443. success = ctx->cmd_cb(RAOP_SETUP);
  444. if ((p = strcasestr(buf, "timing_port")) != NULL) sscanf(p, "%*[^=]=%hu", &tport);
  445. if ((p = strcasestr(buf, "control_port")) != NULL) sscanf(p, "%*[^=]=%hu", &cport);
  446. rtp = rtp_init(ctx->peer, ctx->latency, ctx->rtsp.aeskey, ctx->rtsp.aesiv,
  447. ctx->rtsp.fmtp, cport, tport, ctx->cmd_cb, ctx->data_cb);
  448. ctx->rtp = rtp.ctx;
  449. if ( (cport * tport * rtp.cport * rtp.tport * rtp.aport) != 0 && rtp.ctx) {
  450. char *transport;
  451. asprintf(&transport, "RTP/AVP/UDP;unicast;mode=record;control_port=%u;timing_port=%u;server_port=%u", rtp.cport, rtp.tport, rtp.aport);
  452. LOG_DEBUG("[%p]: audio=(%hu:%hu), timing=(%hu:%hu), control=(%hu:%hu)", ctx, 0, rtp.aport, tport, rtp.tport, cport, rtp.cport);
  453. kd_add(resp, "Transport", transport);
  454. kd_add(resp, "Session", "DEADBEEF");
  455. free(transport);
  456. } else {
  457. success = false;
  458. LOG_INFO("[%p]: cannot start session, missing ports", ctx);
  459. }
  460. } else if (!strcmp(method, "RECORD")) {
  461. unsigned short seqno = 0;
  462. unsigned rtptime = 0;
  463. char *p;
  464. if (ctx->latency) {
  465. char latency[6];
  466. snprintf(latency, 6, "%u", ctx->latency);
  467. kd_add(resp, "Audio-Latency", latency);
  468. }
  469. buf = kd_lookup(headers, "RTP-Info");
  470. if (buf && (p = strcasestr(buf, "seq")) != NULL) sscanf(p, "%*[^=]=%hu", &seqno);
  471. if (buf && (p = strcasestr(buf, "rtptime")) != NULL) sscanf(p, "%*[^=]=%u", &rtptime);
  472. if (ctx->rtp) rtp_record(ctx->rtp, seqno, rtptime);
  473. success = ctx->cmd_cb(RAOP_STREAM);
  474. } else if (!strcmp(method, "FLUSH")) {
  475. unsigned short seqno = 0;
  476. unsigned rtptime = 0;
  477. char *p;
  478. buf = kd_lookup(headers, "RTP-Info");
  479. if ((p = strcasestr(buf, "seq")) != NULL) sscanf(p, "%*[^=]=%hu", &seqno);
  480. if ((p = strcasestr(buf, "rtptime")) != NULL) sscanf(p, "%*[^=]=%u", &rtptime);
  481. // only send FLUSH if useful (discards frames above buffer head and top)
  482. if (ctx->rtp && rtp_flush(ctx->rtp, seqno, rtptime))
  483. success = ctx->cmd_cb(RAOP_FLUSH);
  484. } else if (!strcmp(method, "TEARDOWN")) {
  485. rtp_end(ctx->rtp);
  486. ctx->rtp = NULL;
  487. // need to make sure no search is on-going and reclaim pthread memory
  488. #ifdef WIN32
  489. if (ctx->active_remote.handle) close_mDNS(ctx->active_remote.handle);
  490. pthread_join(ctx->search_thread, NULL);
  491. #else
  492. ctx->active_remote.joiner = xTaskGetCurrentTaskHandle();
  493. ctx->active_remote.running = false;
  494. // task might not need to be resumed anyway
  495. vTaskResume(ctx->active_remote.thread);
  496. ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
  497. vTaskDelete(ctx->active_remote.thread);
  498. heap_caps_free(ctx->active_remote.xTaskBuffer);
  499. LOG_INFO("[%p]: mDNS search task terminated", ctx);
  500. #endif
  501. memset(&ctx->active_remote, 0, sizeof(ctx->active_remote));
  502. NFREE(ctx->rtsp.aeskey);
  503. NFREE(ctx->rtsp.aesiv);
  504. NFREE(ctx->rtsp.fmtp);
  505. success = ctx->cmd_cb(RAOP_STOP);
  506. } else if (!strcmp(method, "SET_PARAMETER")) {
  507. char *p;
  508. if (body && (p = strcasestr(body, "volume")) != NULL) {
  509. float volume;
  510. sscanf(p, "%*[^:]:%f", &volume);
  511. LOG_INFO("[%p]: SET PARAMETER volume %f", ctx, volume);
  512. volume = (volume == -144.0) ? 0 : (1 + volume / 30);
  513. success = ctx->cmd_cb(RAOP_VOLUME, volume);
  514. } else if (body && (p = strcasestr(body, "progress")) != NULL) {
  515. int start, current, stop = 0;
  516. // we want ms, not s
  517. sscanf(p, "%*[^:]:%u/%u/%u", &start, &current, &stop);
  518. current = ((current - start) / 44100) * 1000;
  519. if (stop) stop = ((stop - start) / 44100) * 1000;
  520. else stop = -1;
  521. LOG_INFO("[%p]: SET PARAMETER progress %u/%u %s", ctx, current, stop, p);
  522. success = ctx->cmd_cb(RAOP_PROGRESS, current, stop);
  523. }
  524. if (body && ((p = kd_lookup(headers, "Content-Type")) != NULL) && !strcasecmp(p, "application/x-dmap-tagged")) {
  525. struct metadata_s metadata;
  526. dmap_settings settings = {
  527. NULL, NULL, NULL, NULL, NULL, NULL, NULL, on_dmap_string, NULL,
  528. NULL
  529. };
  530. LOG_INFO("[%p]: received metadata");
  531. settings.ctx = &metadata;
  532. memset(&metadata, 0, sizeof(struct metadata_s));
  533. if (!dmap_parse(&settings, body, len)) {
  534. LOG_INFO("[%p]: received metadata\n\tartist: %s\n\talbum: %s\n\ttitle: %s",
  535. ctx, metadata.artist, metadata.album, metadata.title);
  536. success = ctx->cmd_cb(RAOP_METADATA, metadata.artist, metadata.album, metadata.title);
  537. free_metadata(&metadata);
  538. }
  539. }
  540. }
  541. // don't need to free "buf" because kd_lookup return a pointer, not a strdup
  542. kd_add(resp, "Audio-Jack-Status", "connected; type=analog");
  543. kd_add(resp, "CSeq", kd_lookup(headers, "CSeq"));
  544. if (success) {
  545. buf = http_send(sock, "RTSP/1.0 200 OK", resp);
  546. } else {
  547. buf = http_send(sock, "RTSP/1.0 503 ERROR", NULL);
  548. closesocket(sock);
  549. }
  550. if (strcmp(method, "OPTIONS")) {
  551. LOG_INFO("[%p]: responding:\n%s", ctx, buf ? buf : "<void>");
  552. }
  553. NFREE(body);
  554. NFREE(buf);
  555. kd_free(resp);
  556. kd_free(headers);
  557. return true;
  558. }
  559. /*----------------------------------------------------------------------------*/
  560. #ifdef WIN32
  561. bool search_remote_cb(mDNSservice_t *slist, void *cookie, bool *stop) {
  562. mDNSservice_t *s;
  563. raop_ctx_t *ctx = (raop_ctx_t*) cookie;
  564. // see if we have found an active remote for our ID
  565. for (s = slist; s; s = s->next) {
  566. if (strcasestr(s->name, ctx->active_remote.DACPid)) {
  567. ctx->active_remote.host = s->addr;
  568. ctx->active_remote.port = s->port;
  569. LOG_INFO("[%p]: found ActiveRemote for %s at %s:%u", ctx, ctx->active_remote.DACPid,
  570. inet_ntoa(ctx->active_remote.host), ctx->active_remote.port);
  571. *stop = true;
  572. break;
  573. }
  574. }
  575. // let caller clear list
  576. return false;
  577. }
  578. /*----------------------------------------------------------------------------*/
  579. static void* search_remote(void *args) {
  580. raop_ctx_t *ctx = (raop_ctx_t*) args;
  581. query_mDNS(ctx->active_remote.handle, "_dacp._tcp.local", 0, 0, &search_remote_cb, (void*) ctx);
  582. return NULL;
  583. }
  584. #else
  585. /*----------------------------------------------------------------------------*/
  586. static void* search_remote(void *args) {
  587. raop_ctx_t *ctx = (raop_ctx_t*) args;
  588. bool found = false;
  589. LOG_INFO("starting remote search");
  590. while (ctx->active_remote.running && !found) {
  591. mdns_result_t *results = NULL;
  592. mdns_result_t *r;
  593. mdns_ip_addr_t *a;
  594. if (mdns_query_ptr("_dacp", "_tcp", 3000, 32, &results)) {
  595. LOG_ERROR("mDNS active remote query Failed");
  596. continue;
  597. }
  598. for (r = results; r && !strcasestr(r->instance_name, ctx->active_remote.DACPid); r = r->next);
  599. if (r) {
  600. for (a = r->addr; a && a->addr.type != IPADDR_TYPE_V4; a = a->next);
  601. if (a) {
  602. found = true;
  603. ctx->active_remote.host.s_addr = a->addr.u_addr.ip4.addr;
  604. ctx->active_remote.port = r->port;
  605. LOG_INFO("found remote %s %s:%hu", r->instance_name, inet_ntoa(ctx->active_remote.host), ctx->active_remote.port);
  606. }
  607. }
  608. mdns_query_results_free(results);
  609. }
  610. /*
  611. for some reason which is beyond me, if that tasks gives the semaphore
  612. before the RTSP tasks waits for it, then freeRTOS crashes in queue
  613. management caused by LWIP stack once the RTSP socket is closed. I have
  614. no clue why, but so we'll suspend the tasks as soon as we're done with
  615. search and wait for the resume then give the semaphore
  616. */
  617. // PS: I know this is not fully race-condition free
  618. if (ctx->active_remote.running) vTaskSuspend(NULL);
  619. xTaskNotifyGive(ctx->active_remote.joiner);
  620. // now our context will be deleted
  621. vTaskSuspend(NULL);
  622. return NULL;
  623. }
  624. #endif
  625. /*----------------------------------------------------------------------------*/
  626. static char *rsa_apply(unsigned char *input, int inlen, int *outlen, int mode)
  627. {
  628. static char super_secret_key[] =
  629. "-----BEGIN RSA PRIVATE KEY-----\n"
  630. "MIIEpQIBAAKCAQEA59dE8qLieItsH1WgjrcFRKj6eUWqi+bGLOX1HL3U3GhC/j0Qg90u3sG/1CUt\n"
  631. "wC5vOYvfDmFI6oSFXi5ELabWJmT2dKHzBJKa3k9ok+8t9ucRqMd6DZHJ2YCCLlDRKSKv6kDqnw4U\n"
  632. "wPdpOMXziC/AMj3Z/lUVX1G7WSHCAWKf1zNS1eLvqr+boEjXuBOitnZ/bDzPHrTOZz0Dew0uowxf\n"
  633. "/+sG+NCK3eQJVxqcaJ/vEHKIVd2M+5qL71yJQ+87X6oV3eaYvt3zWZYD6z5vYTcrtij2VZ9Zmni/\n"
  634. "UAaHqn9JdsBWLUEpVviYnhimNVvYFZeCXg/IdTQ+x4IRdiXNv5hEewIDAQABAoIBAQDl8Axy9XfW\n"
  635. "BLmkzkEiqoSwF0PsmVrPzH9KsnwLGH+QZlvjWd8SWYGN7u1507HvhF5N3drJoVU3O14nDY4TFQAa\n"
  636. "LlJ9VM35AApXaLyY1ERrN7u9ALKd2LUwYhM7Km539O4yUFYikE2nIPscEsA5ltpxOgUGCY7b7ez5\n"
  637. "NtD6nL1ZKauw7aNXmVAvmJTcuPxWmoktF3gDJKK2wxZuNGcJE0uFQEG4Z3BrWP7yoNuSK3dii2jm\n"
  638. "lpPHr0O/KnPQtzI3eguhe0TwUem/eYSdyzMyVx/YpwkzwtYL3sR5k0o9rKQLtvLzfAqdBxBurciz\n"
  639. "aaA/L0HIgAmOit1GJA2saMxTVPNhAoGBAPfgv1oeZxgxmotiCcMXFEQEWflzhWYTsXrhUIuz5jFu\n"
  640. "a39GLS99ZEErhLdrwj8rDDViRVJ5skOp9zFvlYAHs0xh92ji1E7V/ysnKBfsMrPkk5KSKPrnjndM\n"
  641. "oPdevWnVkgJ5jxFuNgxkOLMuG9i53B4yMvDTCRiIPMQ++N2iLDaRAoGBAO9v//mU8eVkQaoANf0Z\n"
  642. "oMjW8CN4xwWA2cSEIHkd9AfFkftuv8oyLDCG3ZAf0vrhrrtkrfa7ef+AUb69DNggq4mHQAYBp7L+\n"
  643. "k5DKzJrKuO0r+R0YbY9pZD1+/g9dVt91d6LQNepUE/yY2PP5CNoFmjedpLHMOPFdVgqDzDFxU8hL\n"
  644. "AoGBANDrr7xAJbqBjHVwIzQ4To9pb4BNeqDndk5Qe7fT3+/H1njGaC0/rXE0Qb7q5ySgnsCb3DvA\n"
  645. "cJyRM9SJ7OKlGt0FMSdJD5KG0XPIpAVNwgpXXH5MDJg09KHeh0kXo+QA6viFBi21y340NonnEfdf\n"
  646. "54PX4ZGS/Xac1UK+pLkBB+zRAoGAf0AY3H3qKS2lMEI4bzEFoHeK3G895pDaK3TFBVmD7fV0Zhov\n"
  647. "17fegFPMwOII8MisYm9ZfT2Z0s5Ro3s5rkt+nvLAdfC/PYPKzTLalpGSwomSNYJcB9HNMlmhkGzc\n"
  648. "1JnLYT4iyUyx6pcZBmCd8bD0iwY/FzcgNDaUmbX9+XDvRA0CgYEAkE7pIPlE71qvfJQgoA9em0gI\n"
  649. "LAuE4Pu13aKiJnfft7hIjbK+5kyb3TysZvoyDnb3HOKvInK7vXbKuU4ISgxB2bB3HcYzQMGsz1qJ\n"
  650. "2gG0N5hvJpzwwhbhXqFKA4zaaSrw622wDniAK5MlIE0tIAKKP4yxNGjoD2QYjhBGuhvkWKY=\n"
  651. "-----END RSA PRIVATE KEY-----";
  652. #ifdef WIN32
  653. unsigned char *out;
  654. RSA *rsa;
  655. BIO *bmem = BIO_new_mem_buf(super_secret_key, -1);
  656. rsa = PEM_read_bio_RSAPrivateKey(bmem, NULL, NULL, NULL);
  657. BIO_free(bmem);
  658. out = malloc(RSA_size(rsa));
  659. switch (mode) {
  660. case RSA_MODE_AUTH:
  661. *outlen = RSA_private_encrypt(inlen, input, out, rsa,
  662. RSA_PKCS1_PADDING);
  663. break;
  664. case RSA_MODE_KEY:
  665. *outlen = RSA_private_decrypt(inlen, input, out, rsa,
  666. RSA_PKCS1_OAEP_PADDING);
  667. break;
  668. }
  669. RSA_free(rsa);
  670. return (char*) out;
  671. #else
  672. mbedtls_pk_context pkctx;
  673. mbedtls_rsa_context *trsa;
  674. size_t olen;
  675. /*
  676. we should do entropy initialization & pass a rng function but this
  677. consumes a ton of stack and there is no security concern here. Anyway,
  678. mbedtls takes a lot of stack, unfortunately ...
  679. */
  680. mbedtls_pk_init(&pkctx);
  681. mbedtls_pk_parse_key(&pkctx, (unsigned char *)super_secret_key,
  682. sizeof(super_secret_key), NULL, 0);
  683. uint8_t *outbuf = NULL;
  684. trsa = mbedtls_pk_rsa(pkctx);
  685. switch (mode) {
  686. case RSA_MODE_AUTH:
  687. mbedtls_rsa_set_padding(trsa, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE);
  688. outbuf = malloc(trsa->len);
  689. mbedtls_rsa_pkcs1_encrypt(trsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, inlen, input, outbuf);
  690. *outlen = trsa->len;
  691. break;
  692. case RSA_MODE_KEY:
  693. mbedtls_rsa_set_padding(trsa, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);
  694. outbuf = malloc(trsa->len);
  695. mbedtls_rsa_pkcs1_decrypt(trsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, &olen, input, outbuf, trsa->len);
  696. *outlen = olen;
  697. break;
  698. }
  699. mbedtls_pk_free(&pkctx);
  700. return (char*) outbuf;
  701. #endif
  702. }
  703. #define DECODE_ERROR 0xffffffff
  704. static char base64_chars[] =
  705. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  706. /*----------------------------------------------------------------------------*/
  707. static int base64_pad(char *src, char **padded)
  708. {
  709. int n;
  710. n = strlen(src) + strlen(src) % 4;
  711. *padded = malloc(n + 1);
  712. memset(*padded, '=', n);
  713. memcpy(*padded, src, strlen(src));
  714. (*padded)[n] = '\0';
  715. return strlen(*padded);
  716. }
  717. /*----------------------------------------------------------------------------*/
  718. static int pos(char c)
  719. {
  720. char *p;
  721. for (p = base64_chars; *p; p++)
  722. if (*p == c)
  723. return p - base64_chars;
  724. return -1;
  725. }
  726. /*----------------------------------------------------------------------------*/
  727. static int base64_encode(const void *data, int size, char **str)
  728. {
  729. char *s, *p;
  730. int i;
  731. int c;
  732. const unsigned char *q;
  733. p = s = (char *) malloc(size * 4 / 3 + 4);
  734. if (p == NULL) return -1;
  735. q = (const unsigned char *) data;
  736. i = 0;
  737. for (i = 0; i < size;) {
  738. c = q[i++];
  739. c *= 256;
  740. if (i < size) c += q[i];
  741. i++;
  742. c *= 256;
  743. if (i < size) c += q[i];
  744. i++;
  745. p[0] = base64_chars[(c & 0x00fc0000) >> 18];
  746. p[1] = base64_chars[(c & 0x0003f000) >> 12];
  747. p[2] = base64_chars[(c & 0x00000fc0) >> 6];
  748. p[3] = base64_chars[(c & 0x0000003f) >> 0];
  749. if (i > size) p[3] = '=';
  750. if (i > size + 1) p[2] = '=';
  751. p += 4;
  752. }
  753. *p = 0;
  754. *str = s;
  755. return strlen(s);
  756. }
  757. /*----------------------------------------------------------------------------*/
  758. static unsigned int token_decode(const char *token)
  759. {
  760. int i;
  761. unsigned int val = 0;
  762. int marker = 0;
  763. if (strlen(token) < 4)
  764. return DECODE_ERROR;
  765. for (i = 0; i < 4; i++) {
  766. val *= 64;
  767. if (token[i] == '=')
  768. marker++;
  769. else if (marker > 0)
  770. return DECODE_ERROR;
  771. else
  772. val += pos(token[i]);
  773. }
  774. if (marker > 2)
  775. return DECODE_ERROR;
  776. return (marker << 24) | val;
  777. }
  778. /*----------------------------------------------------------------------------*/
  779. static int base64_decode(const char *str, void *data)
  780. {
  781. const char *p;
  782. unsigned char *q;
  783. q = data;
  784. for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
  785. unsigned int val = token_decode(p);
  786. unsigned int marker = (val >> 24) & 0xff;
  787. if (val == DECODE_ERROR)
  788. return -1;
  789. *q++ = (val >> 16) & 0xff;
  790. if (marker < 2)
  791. *q++ = (val >> 8) & 0xff;
  792. if (marker < 1)
  793. *q++ = val & 0xff;
  794. }
  795. return q - (unsigned char *) data;
  796. }
  797. /*----------------------------------------------------------------------------*/
  798. static void on_dmap_string(void *ctx, const char *code, const char *name, const char *buf, size_t len) {
  799. struct metadata_s *metadata = (struct metadata_s *) ctx;
  800. if (!strcasecmp(code, "asar")) metadata->artist = strndup(buf, len);
  801. else if (!strcasecmp(code, "asal")) metadata->album = strndup(buf, len);
  802. else if (!strcasecmp(code, "minm")) metadata->title = strndup(buf, len);
  803. }