mdnsd.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. /*
  2. * tinysvcmdns - a tiny MDNS implementation for publishing services
  3. * Copyright (C) 2011 Darell Tan
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. The name of the author may not be used to endorse or promote products
  15. * derived from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #ifdef _WIN32
  29. #include <winsock2.h>
  30. #include <ws2tcpip.h>
  31. #define LOG_ERR 3
  32. #else
  33. #include <sys/select.h>
  34. #include <sys/socket.h>
  35. #include <sys/ioctl.h>
  36. #include <netinet/in.h>
  37. #include <arpa/inet.h>
  38. #include <net/if.h>
  39. #include <syslog.h>
  40. #endif
  41. #include <sys/types.h>
  42. #include <sys/stat.h>
  43. #include <fcntl.h>
  44. #include <signal.h>
  45. #include <string.h>
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <stdarg.h>
  49. #ifndef _WIN32
  50. #include <unistd.h>
  51. #endif
  52. #include <assert.h>
  53. #if __has_include(<pthread.h>)
  54. #include <pthread.h>
  55. #define mutex_lock(m) pthread_mutex_lock(&m);
  56. #define mutex_unlock(m) pthread_mutex_unlock(&m);
  57. #elif _WIN32
  58. #define USE_WIN32_THREAD
  59. #define mutex_lock(m) WaitForSingleObject(m, INFINITE);
  60. #define mutex_unlock(m) ReleaseMutex(m);
  61. #else
  62. #error missing pthread
  63. #endif
  64. #include "mdns.h"
  65. #include "mdnssvc.h"
  66. #if _MSC_VER
  67. #define ssize_t SSIZE_T
  68. #endif
  69. #define MDNS_ADDR "224.0.0.251"
  70. #define MDNS_PORT 5353
  71. #define PACKET_SIZE 65536
  72. #define SERVICES_DNS_SD_NLABEL \
  73. ((uint8_t *) "\x09_services\x07_dns-sd\x04_udp\x05local")
  74. #define log_message(l,f,...) mdnsd_log(true, f, ##__VA_ARGS__)
  75. struct mdnsd {
  76. #ifdef USE_WIN32_THREAD
  77. HANDLE data_lock;
  78. #else
  79. pthread_mutex_t data_lock;
  80. #endif
  81. int sockfd;
  82. int notify_pipe[2];
  83. int stop_flag;
  84. struct rr_group *group;
  85. struct rr_list *announce;
  86. struct rr_list *services;
  87. struct rr_list *leave;
  88. uint8_t *hostname;
  89. };
  90. struct mdns_service {
  91. struct rr_list *entries;
  92. };
  93. static bool log_verbose;
  94. /////////////////////////////////
  95. void mdnsd_log(bool force, char* fmt, ...) {
  96. if (force || log_verbose) {
  97. va_list ap;
  98. va_start(ap, fmt);
  99. int size = vsnprintf(NULL, 0, fmt, ap);
  100. if (size > 0) {
  101. char* buf = malloc(size + 1);
  102. vsprintf(buf, fmt, ap);
  103. fprintf(stderr, "%s", buf);
  104. free(buf);
  105. }
  106. va_end(ap);
  107. }
  108. }
  109. static int create_recv_sock(uint32_t host) {
  110. int sd = socket(AF_INET, SOCK_DGRAM, 0);
  111. int r = -1;
  112. int on = 1;
  113. char onChar = 1;
  114. struct sockaddr_in serveraddr;
  115. struct ip_mreq mreq;
  116. unsigned char ttl = 255;
  117. if (sd < 0) {
  118. log_message(LOG_ERR, "recv socket(): %m\n");
  119. return sd;
  120. }
  121. if ((r = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on))) < 0) {
  122. log_message(LOG_ERR, "recv setsockopt(SO_REUSEADDR): %m\n");
  123. return r;
  124. }
  125. #if !defined(_WIN32)
  126. socklen_t len = sizeof(on);
  127. if (!getsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, &len)) {
  128. on = 1;
  129. if ((r = setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) < 0) {
  130. log_message(LOG_ERR, "recv setsockopt(SO_REUSEPORT): %m\n", r);
  131. }
  132. }
  133. #endif
  134. /* bind to an address */
  135. memset(&serveraddr, 0, sizeof(serveraddr));
  136. serveraddr.sin_family = AF_INET;
  137. serveraddr.sin_port = htons(MDNS_PORT);
  138. serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); /* receive multicast */
  139. if ((r = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0) {
  140. log_message(LOG_ERR, "recv bind(): %m\n");
  141. return r;
  142. }
  143. memset(&mreq, 0, sizeof(struct ip_mreq));
  144. mreq.imr_interface.s_addr = host;
  145. if ((r = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char*) &mreq.imr_interface.s_addr, sizeof(mreq.imr_interface.s_addr))) < 0) {
  146. log_message(LOG_ERR, "recv setsockopt(IP_PROTO_IP): %m\n");
  147. return r;
  148. }
  149. if ((r = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, (void*) &ttl, sizeof(ttl))) < 0) {
  150. log_message(LOG_ERR, "recv setsockopt(IP_MULTICAST_IP): %m\n");
  151. return r;
  152. }
  153. // add membership to receiving socket
  154. mreq.imr_multiaddr.s_addr = inet_addr(MDNS_ADDR);
  155. if ((r = setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq))) < 0) {
  156. log_message(LOG_ERR, "recv setsockopt(IP_ADD_MEMBERSHIP): %m\n");
  157. return r;
  158. }
  159. // enable loopback in case someone else needs the data
  160. if ((r = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &onChar, sizeof(onChar))) < 0) {
  161. log_message(LOG_ERR, "recv setsockopt(IP_MULTICAST_LOOP): %m\n");
  162. return r;
  163. }
  164. #ifdef IP_PKTINFO
  165. on = 1;
  166. if ((r = setsockopt(sd, IPPROTO_IP, IP_PKTINFO, (char *) &on, sizeof(on))) < 0) {
  167. log_message(LOG_ERR, "recv setsockopt(IP_PKTINFO): %m\n");
  168. return r;
  169. }
  170. #endif
  171. return sd;
  172. }
  173. static ssize_t send_packet(int fd, const void *data, size_t len) {
  174. static struct sockaddr_in toaddr;
  175. if (toaddr.sin_family != AF_INET) {
  176. memset(&toaddr, 0, sizeof(struct sockaddr_in));
  177. toaddr.sin_family = AF_INET;
  178. toaddr.sin_port = htons(MDNS_PORT);
  179. toaddr.sin_addr.s_addr = inet_addr(MDNS_ADDR);
  180. }
  181. return sendto(fd, data, len, 0, (struct sockaddr *) &toaddr, sizeof(struct sockaddr_in));
  182. }
  183. // populate the specified list which matches the RR name and type
  184. // type can be RR_ANY, which populates all entries EXCEPT RR_NSEC
  185. static int populate_answers(struct mdnsd *svr, struct rr_list **rr_head, uint8_t *name, enum rr_type type) {
  186. int num_ans = 0;
  187. struct rr_group *ans_grp;
  188. struct rr_list *n;
  189. // check if we have the records
  190. mutex_lock(svr->data_lock);
  191. ans_grp = rr_group_find(svr->group, name);
  192. if (ans_grp == NULL) {
  193. mutex_unlock(svr->data_lock);
  194. return num_ans;
  195. }
  196. // decide which records should go into answers
  197. n = ans_grp->rr;
  198. for (; n; n = n->next) {
  199. // exclude NSEC for RR_ANY
  200. if (type == RR_ANY && n->e->type == RR_NSEC)
  201. continue;
  202. if ((type == n->e->type || type == RR_ANY) && cmp_nlabel(name, n->e->name) == 0) {
  203. num_ans += rr_list_append(rr_head, n->e);
  204. }
  205. }
  206. mutex_unlock(svr->data_lock);
  207. return num_ans;
  208. }
  209. // given a list of RRs, look up related records and add them
  210. static void add_related_rr(struct mdnsd *svr, struct rr_list *list, struct mdns_pkt *reply) {
  211. for (; list; list = list->next) {
  212. struct rr_entry *ans = list->e;
  213. switch (ans->type) {
  214. case RR_PTR:
  215. // target host A, AAAA records
  216. reply->num_add_rr += populate_answers(svr, &reply->rr_add,
  217. MDNS_RR_GET_PTR_NAME(ans), RR_ANY);
  218. break;
  219. case RR_SRV:
  220. // target host A, AAAA records
  221. reply->num_add_rr += populate_answers(svr, &reply->rr_add,
  222. ans->data.SRV.target, RR_ANY);
  223. // perhaps TXT records of the same name?
  224. // if we use RR_ANY, we risk pulling in the same RR_SRV
  225. reply->num_add_rr += populate_answers(svr, &reply->rr_add,
  226. ans->name, RR_TXT);
  227. break;
  228. case RR_A:
  229. case RR_AAAA:
  230. reply->num_add_rr += populate_answers(svr, &reply->rr_add,
  231. ans->name, RR_NSEC);
  232. break;
  233. default:
  234. // nothing to add
  235. break;
  236. }
  237. }
  238. }
  239. // creates an announce packet given the type name PTR
  240. static void announce_srv(struct mdnsd *svr, struct mdns_pkt *reply, uint8_t *name) {
  241. mdns_init_reply(reply, 0);
  242. reply->num_ans_rr += populate_answers(svr, &reply->rr_ans, name, RR_PTR);
  243. // remember to add the services dns-sd PTR too
  244. reply->num_ans_rr += populate_answers(svr, &reply->rr_ans,
  245. SERVICES_DNS_SD_NLABEL, RR_PTR);
  246. // see if we can match additional records for answers
  247. add_related_rr(svr, reply->rr_ans, reply);
  248. // additional records for additional records
  249. add_related_rr(svr, reply->rr_add, reply);
  250. }
  251. // processes the incoming MDNS packet
  252. // returns >0 if processed, 0 otherwise
  253. static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct mdns_pkt *reply) {
  254. int i;
  255. struct rr_list *qnl;
  256. struct rr_list *ans, *prev_ans;
  257. assert(pkt != NULL);
  258. // is it standard query?
  259. if ((pkt->flags & MDNS_FLAG_RESP) == 0 &&
  260. MDNS_FLAG_GET_OPCODE(pkt->flags) == 0) {
  261. mdns_init_reply(reply, pkt->id);
  262. DEBUG_PRINTF("flags = %04x, qn = %d, ans = %d, add = %d\n",
  263. pkt->flags,
  264. pkt->num_qn,
  265. pkt->num_ans_rr,
  266. pkt->num_add_rr);
  267. // loop through questions
  268. qnl = pkt->rr_qn;
  269. for (i = 0; i < pkt->num_qn; i++, qnl = qnl->next) {
  270. struct rr_entry *qn = qnl->e;
  271. int num_ans_added = 0;
  272. char *namestr = nlabel_to_str(qn->name);
  273. DEBUG_PRINTF("qn #%d: type %s (%02x) %s - ", i, rr_get_type_name(qn->type), qn->type, namestr);
  274. free(namestr);
  275. // mark that a unicast response is desired
  276. reply->unicast |= qn->unicast_query;
  277. num_ans_added = populate_answers(svr, &reply->rr_ans, qn->name, qn->type);
  278. reply->num_ans_rr += num_ans_added;
  279. DEBUG_PRINTF("added %d answers\n", num_ans_added);
  280. }
  281. // remove our replies if they were already in their answers
  282. ans = NULL; prev_ans = NULL;
  283. for (ans = reply->rr_ans; ans; ) {
  284. struct rr_list *next_ans = ans->next;
  285. struct rr_entry *known_ans = rr_entry_match(pkt->rr_ans, ans->e);
  286. // discard answers that have at least half of the actual TTL
  287. if (known_ans != NULL && known_ans->ttl >= ans->e->ttl / 2) {
  288. char *namestr = nlabel_to_str(ans->e->name);
  289. DEBUG_PRINTF("removing answer for %s\n", namestr);
  290. free(namestr);
  291. // check if list item is head
  292. if (prev_ans == NULL)
  293. reply->rr_ans = ans->next;
  294. else
  295. prev_ans->next = ans->next;
  296. free(ans);
  297. ans = prev_ans;
  298. // adjust answer count
  299. reply->num_ans_rr--;
  300. }
  301. prev_ans = ans;
  302. ans = next_ans;
  303. }
  304. // see if we can match additional records for answers
  305. add_related_rr(svr, reply->rr_ans, reply);
  306. // additional records for additional records
  307. add_related_rr(svr, reply->rr_add, reply);
  308. DEBUG_PRINTF("\n");
  309. return reply->num_ans_rr;
  310. }
  311. return 0;
  312. }
  313. int create_pipe(int handles[2]) {
  314. #ifdef _WIN32
  315. SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
  316. struct sockaddr_in serv_addr;
  317. int len;
  318. if (sock == INVALID_SOCKET) {
  319. return -1;
  320. }
  321. memset(&serv_addr, 0, sizeof(serv_addr));
  322. serv_addr.sin_family = AF_INET;
  323. serv_addr.sin_port = htons(0);
  324. serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  325. if (bind(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR) {
  326. closesocket(sock);
  327. return -1;
  328. }
  329. if (listen(sock, 1) == SOCKET_ERROR) {
  330. closesocket(sock);
  331. return -1;
  332. }
  333. len = sizeof(serv_addr);
  334. if (getsockname(sock, (SOCKADDR*)&serv_addr, &len) == SOCKET_ERROR) {
  335. closesocket(sock);
  336. return -1;
  337. }
  338. if ((handles[1] = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
  339. closesocket(sock);
  340. return -1;
  341. }
  342. if (connect(handles[1], (struct sockaddr*)&serv_addr, len) == SOCKET_ERROR) {
  343. closesocket(sock);
  344. return -1;
  345. }
  346. if ((handles[0] = accept(sock, (struct sockaddr*)&serv_addr, &len)) == INVALID_SOCKET) {
  347. closesocket((SOCKET)handles[1]);
  348. handles[1] = INVALID_SOCKET;
  349. closesocket(sock);
  350. return -1;
  351. }
  352. closesocket(sock);
  353. return 0;
  354. #else
  355. return pipe(handles);
  356. #endif
  357. }
  358. int read_pipe(int s, char* buf, int len) {
  359. #ifdef _WIN32
  360. int ret = recv(s, buf, len, 0);
  361. if (ret < 0 && WSAGetLastError() == WSAECONNRESET) {
  362. ret = 0;
  363. }
  364. return ret;
  365. #else
  366. return read(s, buf, len);
  367. #endif
  368. }
  369. int write_pipe(int s, char* buf, int len) {
  370. #ifdef _WIN32
  371. return send(s, buf, len, 0);
  372. #else
  373. return write(s, buf, len);
  374. #endif
  375. }
  376. int close_pipe(int s) {
  377. #ifdef _WIN32
  378. return closesocket(s);
  379. #else
  380. return close(s);
  381. #endif
  382. }
  383. // main loop to receive, process and send out MDNS replies
  384. // also handles MDNS service announces
  385. static void main_loop(struct mdnsd *svr) {
  386. fd_set sockfd_set;
  387. int max_fd = svr->sockfd;
  388. char notify_buf[2]; // buffer for reading of notify_pipe
  389. struct mdns_pkt *mdns_reply;
  390. struct mdns_pkt *mdns;
  391. struct rr_list *svc_le;
  392. void *pkt_buffer = malloc(PACKET_SIZE);
  393. if (svr->notify_pipe[0] > max_fd)
  394. max_fd = svr->notify_pipe[0];
  395. mdns_reply = malloc(sizeof(struct mdns_pkt));
  396. memset(mdns_reply, 0, sizeof(struct mdns_pkt));
  397. while (! svr->stop_flag) {
  398. FD_ZERO(&sockfd_set);
  399. FD_SET(svr->sockfd, &sockfd_set);
  400. FD_SET(svr->notify_pipe[0], &sockfd_set);
  401. select(max_fd + 1, &sockfd_set, NULL, NULL, NULL);
  402. if (FD_ISSET(svr->notify_pipe[0], &sockfd_set)) {
  403. // flush the notify_pipe
  404. read_pipe(svr->notify_pipe[0], (char*)&notify_buf, 1);
  405. } else if (FD_ISSET(svr->sockfd, &sockfd_set)) {
  406. struct sockaddr_in fromaddr;
  407. socklen_t sockaddr_size = sizeof(struct sockaddr_in);
  408. ssize_t recvsize = recvfrom(svr->sockfd, pkt_buffer, PACKET_SIZE, 0,
  409. (struct sockaddr *) &fromaddr, &sockaddr_size);
  410. if (recvsize < 0) {
  411. log_message(LOG_ERR, "recv(): %m\n");
  412. }
  413. DEBUG_PRINTF("data from=%s size=%ld\n", inet_ntoa(fromaddr.sin_addr), (long) recvsize);
  414. mdns = mdns_parse_pkt(pkt_buffer, recvsize);
  415. if (mdns != NULL) {
  416. if (process_mdns_pkt(svr, mdns, mdns_reply)) {
  417. size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
  418. if (mdns_reply->unicast) {
  419. int sock = socket(fromaddr.sin_family, SOCK_DGRAM, 0);
  420. sendto(sock, pkt_buffer, replylen, 0, (void*) &fromaddr, sizeof(struct sockaddr_in));
  421. DEBUG_PRINTF("unicast answer\n");
  422. #ifdef _WIN32
  423. closesocket(sock);
  424. #else
  425. close(sock);
  426. #endif
  427. } else {
  428. send_packet(svr->sockfd, pkt_buffer, replylen);
  429. }
  430. } else if (mdns->num_qn == 0) {
  431. DEBUG_PRINTF("(no questions in packet)\n\n");
  432. }
  433. mdns_pkt_destroy(mdns);
  434. }
  435. }
  436. // send out announces
  437. while (1) {
  438. struct rr_entry *ann_e = NULL;
  439. char *namestr;
  440. // extract from head of list
  441. mutex_lock(svr->data_lock);
  442. if (svr->announce)
  443. ann_e = rr_list_remove(&svr->announce, svr->announce->e);
  444. mutex_unlock(svr->data_lock);
  445. if (! ann_e)
  446. break;
  447. namestr = nlabel_to_str(ann_e->name);
  448. DEBUG_PRINTF("sending announce for %s\n", namestr);
  449. free(namestr);
  450. announce_srv(svr, mdns_reply, ann_e->name);
  451. if (mdns_reply->num_ans_rr > 0) {
  452. size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
  453. send_packet(svr->sockfd, pkt_buffer, replylen);
  454. }
  455. }
  456. // send out bye-bye for terminating services
  457. while (1) {
  458. struct rr_entry *leave_e = NULL;
  459. char *namestr;
  460. mutex_lock(svr->data_lock);
  461. if (svr->leave)
  462. leave_e = rr_list_remove(&svr->leave, svr->leave->e);
  463. mutex_unlock(svr->data_lock);
  464. if (!leave_e)
  465. break;
  466. mdns_init_reply(mdns_reply, 0);
  467. namestr = nlabel_to_str(leave_e->name);
  468. DEBUG_PRINTF("sending bye-bye for %s\n", namestr);
  469. free(namestr);
  470. leave_e->ttl = 0;
  471. mdns_reply->num_ans_rr += rr_list_append(&mdns_reply->rr_ans, leave_e);
  472. // send out packet
  473. if (mdns_reply->num_ans_rr > 0) {
  474. size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
  475. send_packet(svr->sockfd, pkt_buffer, replylen);
  476. }
  477. rr_entry_destroy(leave_e->data.PTR.entry);
  478. rr_entry_destroy(leave_e);
  479. }
  480. }
  481. // main thread terminating. send out "goodbye packets" for services
  482. mdns_init_reply(mdns_reply, 0);
  483. mutex_lock(svr->data_lock);
  484. svc_le = svr->services;
  485. for (; svc_le; svc_le = svc_le->next) {
  486. // set TTL to zero
  487. svc_le->e->ttl = 0;
  488. mdns_reply->num_ans_rr += rr_list_append(&mdns_reply->rr_ans, svc_le->e);
  489. }
  490. mutex_unlock(svr->data_lock);
  491. // send out packet
  492. if (mdns_reply->num_ans_rr > 0) {
  493. size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
  494. send_packet(svr->sockfd, pkt_buffer, replylen);
  495. }
  496. // destroy packet
  497. mdns_init_reply(mdns_reply, 0);
  498. free(mdns_reply);
  499. free(pkt_buffer);
  500. close_pipe(svr->sockfd);
  501. svr->stop_flag = 2;
  502. }
  503. /////////////////////////////////////////////////////
  504. void mdnsd_set_hostname(struct mdnsd *svr, const char *hostname, struct in_addr addr) {
  505. struct rr_entry *a_e = NULL,
  506. *nsec_e = NULL;
  507. // currently can't be called twice
  508. // dont ask me what happens if the IP changes
  509. assert(svr->hostname == NULL);
  510. a_e = rr_create_a(create_nlabel(hostname), addr);
  511. nsec_e = rr_create(create_nlabel(hostname), RR_NSEC);
  512. nsec_e->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME;
  513. rr_set_nsec(nsec_e, RR_A);
  514. mutex_lock(svr->data_lock);
  515. svr->hostname = create_nlabel(hostname);
  516. rr_group_add(&svr->group, a_e);
  517. rr_group_add(&svr->group, nsec_e);
  518. mutex_unlock(svr->data_lock);
  519. }
  520. void mdnsd_set_hostname_v6(struct mdnsd *svr, const char *hostname, struct in6_addr *addr) {
  521. struct rr_entry *aaaa_e = NULL, *nsec_e = NULL;
  522. // currently can't be called twice
  523. // dont ask me what happens if the IP changes
  524. assert(svr->hostname == NULL);
  525. aaaa_e = rr_create_aaaa(create_nlabel(hostname), addr); // 120 seconds automatically
  526. nsec_e = rr_create(create_nlabel(hostname), RR_NSEC);
  527. nsec_e->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // set to 120 seconds (default is 4500)
  528. rr_set_nsec(nsec_e, RR_AAAA);
  529. mutex_lock(svr->data_lock);
  530. svr->hostname = create_nlabel(hostname);
  531. rr_group_add(&svr->group, aaaa_e);
  532. rr_group_add(&svr->group, nsec_e);
  533. mutex_unlock(svr->data_lock);
  534. }
  535. void mdnsd_add_rr(struct mdnsd *svr, struct rr_entry *rr) {
  536. mutex_lock(svr->data_lock);
  537. rr_group_add(&svr->group, rr);
  538. mutex_unlock(svr->data_lock);
  539. }
  540. struct mdns_service *mdnsd_register_svc(struct mdnsd *svr, const char *instance_name,
  541. const char *type, uint16_t port, const char *hostname, const char *txt[]) {
  542. struct rr_entry *txt_e = NULL,
  543. *srv_e = NULL,
  544. *ptr_e = NULL,
  545. *bptr_e = NULL;
  546. uint8_t *target;
  547. uint8_t *inst_nlabel, *type_nlabel, *nlabel;
  548. struct mdns_service *service = malloc(sizeof(struct mdns_service));
  549. memset(service, 0, sizeof(struct mdns_service));
  550. // combine service name
  551. type_nlabel = create_nlabel(type);
  552. inst_nlabel = create_label(instance_name);
  553. nlabel = join_nlabel(inst_nlabel, type_nlabel);
  554. // create TXT record
  555. if (txt && *txt) {
  556. txt_e = rr_create(dup_nlabel(nlabel), RR_TXT);
  557. rr_list_append(&service->entries, txt_e);
  558. // add TXTs
  559. for (; *txt; txt++)
  560. rr_add_txt(txt_e, *txt);
  561. }
  562. // create SRV record
  563. assert(hostname || svr->hostname); // either one as target
  564. target = hostname ?
  565. create_nlabel(hostname) :
  566. dup_nlabel(svr->hostname);
  567. srv_e = rr_create_srv(dup_nlabel(nlabel), port, target);
  568. rr_list_append(&service->entries, srv_e);
  569. // create PTR record for type
  570. ptr_e = rr_create_ptr(type_nlabel, srv_e);
  571. // create services PTR record for type
  572. // this enables the type to show up as a "service"
  573. bptr_e = rr_create_ptr(dup_nlabel(SERVICES_DNS_SD_NLABEL), ptr_e);
  574. // modify lists here
  575. mutex_lock(svr->data_lock);
  576. if (txt_e)
  577. rr_group_add(&svr->group, txt_e);
  578. rr_group_add(&svr->group, srv_e);
  579. rr_group_add(&svr->group, ptr_e);
  580. rr_group_add(&svr->group, bptr_e);
  581. // append PTR entry to announce list
  582. rr_list_append(&svr->announce, ptr_e);
  583. rr_list_append(&svr->services, ptr_e);
  584. mutex_unlock(svr->data_lock);
  585. // don't free type_nlabel - it's with the PTR record
  586. free(nlabel);
  587. free(inst_nlabel);
  588. // notify server
  589. write_pipe(svr->notify_pipe[1], ".", 1);
  590. return service;
  591. }
  592. void mdns_service_remove(struct mdnsd *svr, struct mdns_service *svc) {
  593. struct rr_list *rr;
  594. assert(svr != NULL && svc != NULL);
  595. // modify lists here
  596. mutex_lock(svr->data_lock);
  597. for (rr = svc->entries; rr; rr = rr->next) {
  598. struct rr_group *g;
  599. struct rr_entry *ptr_e;
  600. // remove entry from groups and destroy entries that are not PTR
  601. if ((g = rr_group_find(svr->group, rr->e->name)) != NULL) {
  602. rr_list_remove(&g->rr, rr->e);
  603. }
  604. // remove PTR and BPTR related to this SVC
  605. if ((ptr_e = rr_entry_remove(svr->group, rr->e, RR_PTR)) != NULL) {
  606. struct rr_entry *bptr_e;
  607. // remove PTR from announce and services
  608. rr_list_remove(&svr->announce, ptr_e);
  609. rr_list_remove(&svr->services, ptr_e);
  610. // find BPTR and remove it from groups
  611. bptr_e = rr_entry_remove(svr->group, ptr_e, RR_PTR);
  612. rr_entry_destroy(bptr_e);
  613. // add PTR to list of announces for leaving
  614. rr_list_append(&svr->leave, ptr_e);
  615. } else {
  616. // destroy entries not needed for sending "leave" packet
  617. rr_entry_destroy(rr->e);
  618. }
  619. }
  620. // remove all empty groups
  621. rr_group_clean(&svr->group);
  622. // destroy this service entries
  623. rr_list_destroy(svc->entries, 0);
  624. free(svc);
  625. mutex_unlock(svr->data_lock);
  626. }
  627. void mdns_service_destroy(struct mdns_service *srv) {
  628. assert(srv != NULL);
  629. rr_list_destroy(srv->entries, 0);
  630. free(srv);
  631. }
  632. struct mdnsd *mdnsd_start(struct in_addr host, bool verbose) {
  633. #ifndef USE_WIN32_THREAD
  634. pthread_t tid;
  635. pthread_attr_t attr;
  636. #endif
  637. log_verbose = verbose;
  638. struct mdnsd *server = malloc(sizeof(struct mdnsd));
  639. memset(server, 0, sizeof(struct mdnsd));
  640. if (create_pipe(server->notify_pipe) != 0) {
  641. log_message(LOG_ERR, "pipe(): %m\n");
  642. free(server);
  643. return NULL;
  644. }
  645. server->sockfd = create_recv_sock(host.s_addr);
  646. if (server->sockfd < 0) {
  647. log_message(LOG_ERR, "unable to create recv socket\n");
  648. free(server);
  649. return NULL;
  650. }
  651. #ifdef USE_WIN32_THREAD
  652. server->data_lock = CreateMutex(NULL, FALSE, NULL);
  653. #else
  654. pthread_mutex_init(&server->data_lock, NULL);
  655. #endif
  656. #ifdef USE_WIN32_THREAD
  657. if (CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) main_loop, (void*) server, 0, NULL) == NULL) {
  658. CloseHandle(server->data_lock);
  659. #else
  660. // init thread
  661. pthread_attr_init(&attr);
  662. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  663. if (pthread_create(&tid, &attr, (void *(*)(void *)) main_loop, (void *) server) != 0) {
  664. pthread_mutex_destroy(&server->data_lock);
  665. #endif
  666. free(server);
  667. return NULL;
  668. }
  669. return server;
  670. }
  671. void mdnsd_stop(struct mdnsd *s) {
  672. struct timeval tv;
  673. if (!s) return;
  674. tv.tv_sec = 0;
  675. tv.tv_usec = 500*1000;
  676. assert(s != NULL);
  677. s->stop_flag = 1;
  678. write_pipe(s->notify_pipe[1], ".", 1);
  679. while (s->stop_flag != 2)
  680. select(0, NULL, NULL, NULL, &tv);
  681. close_pipe(s->notify_pipe[0]);
  682. close_pipe(s->notify_pipe[1]);
  683. #ifdef USE_WIN32_THREAD
  684. CloseHandle(s->data_lock);
  685. #else
  686. pthread_mutex_destroy(&s->data_lock);
  687. #endif
  688. rr_group_destroy(s->group);
  689. rr_list_destroy(s->announce, 0);
  690. rr_list_destroy(s->services, 0);
  691. rr_list_destroy(s->leave, 0);
  692. if (s->hostname)
  693. free(s->hostname);
  694. free(s);
  695. }