climdnssvc.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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. #ifndef _WIN32
  29. #define _GNU_SOURCE
  30. #endif
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <stdbool.h>
  35. #include <signal.h>
  36. #include <stdint.h>
  37. #ifdef _WIN32
  38. #include <winsock2.h>
  39. #include <iphlpapi.h>
  40. #pragma comment(lib, "IPHLPAPI.lib")
  41. typedef uint32_t in_addr_t;
  42. #define strcasecmp stricmp
  43. #elif defined (__linux__) || defined (__FreeBSD__) || defined (sun)
  44. #include <unistd.h>
  45. #include <sys/socket.h>
  46. #include <netdb.h>
  47. #include <arpa/inet.h>
  48. #include <sys/ioctl.h>
  49. #include <net/if.h>
  50. #include <strings.h>
  51. #include <ifaddrs.h>
  52. #if defined (__FreeBSD__) || defined (sun)
  53. #include <net/if_dl.h>
  54. #include <net/if_types.h>
  55. #endif
  56. #if defined (sun)
  57. #include <sys/sockio.h>
  58. #endif
  59. #elif defined (__APPLE__)
  60. #include <unistd.h>
  61. #include <sys/socket.h>
  62. #include <netdb.h>
  63. #include <arpa/inet.h>
  64. #include <sys/ioctl.h>
  65. #include <net/if.h>
  66. #include <ifaddrs.h>
  67. #endif
  68. #include "mdnssvc.h"
  69. struct mdns_service *svc;
  70. struct mdnsd *svr;
  71. /*---------------------------------------------------------------------------*/
  72. #ifdef _WIN32
  73. static void winsock_init(void) {
  74. WSADATA wsaData;
  75. WORD wVersionRequested = MAKEWORD(2, 2);
  76. int WSerr = WSAStartup(wVersionRequested, &wsaData);
  77. if (WSerr != 0) exit(1);
  78. }
  79. /*---------------------------------------------------------------------------*/
  80. static void winsock_close(void) {
  81. WSACleanup();
  82. }
  83. #endif
  84. /*---------------------------------------------------------------------------*/
  85. struct in_addr get_interface(char* iface) {
  86. struct in_addr addr;
  87. // try to get the address from the parameter
  88. addr.s_addr = iface && *iface ? inet_addr(iface) : INADDR_NONE;
  89. // if we already are given an address; just use it
  90. if (addr.s_addr != INADDR_NONE) return addr;
  91. #ifdef _WIN32
  92. struct sockaddr_in* host = NULL;
  93. ULONG size = sizeof(IP_ADAPTER_ADDRESSES) * 32;
  94. // otherwise we need to loop and find somethign that works
  95. IP_ADAPTER_ADDRESSES* adapters = (IP_ADAPTER_ADDRESSES*)malloc(size);
  96. int ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_GATEWAYS | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST, 0, adapters, &size);
  97. for (PIP_ADAPTER_ADDRESSES adapter = adapters; adapter; adapter = adapter->Next) {
  98. if (adapter->TunnelType == TUNNEL_TYPE_TEREDO ||
  99. adapter->OperStatus != IfOperStatusUp || 0)
  100. continue;
  101. char name[256];
  102. wcstombs(name, adapter->FriendlyName, sizeof(name));
  103. if (iface && *iface && strcasecmp(iface, name)) continue;
  104. for (IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress; unicast;
  105. unicast = unicast->Next) {
  106. if (adapter->FirstGatewayAddress && unicast->Address.lpSockaddr->sa_family == AF_INET) {
  107. addr = ((struct sockaddr_in*)unicast->Address.lpSockaddr)->sin_addr;
  108. return addr;
  109. }
  110. }
  111. }
  112. return addr;
  113. #else
  114. struct ifaddrs* ifaddr;
  115. if (getifaddrs(&ifaddr) == -1) return addr;
  116. for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
  117. if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET ||
  118. !(ifa->ifa_flags & IFF_UP) || !(ifa->ifa_flags & IFF_MULTICAST) ||
  119. ifa->ifa_flags & IFF_LOOPBACK ||
  120. (iface && *iface && strcasecmp(iface, ifa->ifa_name)))
  121. continue;
  122. addr = ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr;
  123. break;
  124. }
  125. freeifaddrs(ifaddr);
  126. return addr;
  127. #endif
  128. }
  129. #ifdef _WIN32
  130. /*----------------------------------------------------------------------------*/
  131. int asprintf(char** strp, const char* fmt, ...)
  132. {
  133. va_list args;
  134. va_start(args, fmt);
  135. int len = vsnprintf(NULL, 0, fmt, args);
  136. *strp = malloc(len + 1);
  137. if (*strp) len = vsprintf(*strp, fmt, args);
  138. else len = 0;
  139. va_end(args);
  140. return len;
  141. }
  142. #endif
  143. /*---------------------------------------------------------------------------*/
  144. static void print_usage(void) {
  145. printf("[-v] [-o <ip|ifname>] -i <identity> -t <type> -p <port> [<txt>] ...[<txt>]\n");
  146. }
  147. /*---------------------------------------------------------------------------*/
  148. static void sighandler(int signum) {
  149. mdnsd_stop(svr);
  150. #ifdef _WIN32
  151. winsock_close();
  152. #endif
  153. exit(0);
  154. }
  155. /*---------------------------------------------------------------------------*/
  156. /* */
  157. /*---------------------------------------------------------------------------*/
  158. int main(int argc, char *argv[]) {
  159. const char** txt = NULL;
  160. struct in_addr host;
  161. char hostname[256],* arg, * identity = NULL, * type = NULL, * addr = NULL;
  162. int port = 0;
  163. bool verbose = false;
  164. if (argc <= 2) {
  165. print_usage();
  166. exit(0);
  167. }
  168. #ifdef _WIN32
  169. winsock_init();
  170. #endif
  171. signal(SIGINT, sighandler);
  172. signal(SIGTERM, sighandler);
  173. #if defined(SIGPIPE)
  174. signal(SIGPIPE, SIG_IGN);
  175. #endif
  176. #if defined(SIGQUIT)
  177. signal(SIGQUIT, sighandler);
  178. #endif
  179. #if defined(SIGHUP)
  180. signal(SIGHUP, sighandler);
  181. #endif
  182. while ((arg = *++argv) != NULL) {
  183. if (!strcasecmp(arg, "-o") || !strcasecmp(arg, "host")) {
  184. addr = *++argv;
  185. argc -= 2;
  186. } else if (!strcasecmp(arg, "-p")) {
  187. port = atoi(*++argv);
  188. } else if (!strcasecmp(arg, "-v")) {
  189. verbose = true;
  190. } else if (!strcasecmp(arg, "-t")) {
  191. (void)! asprintf(&type, "%s.local", *++argv);
  192. } else if (!strcasecmp(arg, "-i")) {
  193. identity = *++argv;
  194. } else {
  195. // nothing let's try to be smart and handle legacy crap
  196. if (!identity) identity = *argv;
  197. else if (!type) (void) !asprintf(&type, "%s.local", *argv);
  198. else if (!port) port = atoi(*argv);
  199. else {
  200. txt = (const char**) malloc((argc + 1) * sizeof(char**));
  201. memcpy(txt, argv, argc * sizeof(char**));
  202. txt[argc] = NULL;
  203. break;
  204. }
  205. argc--;
  206. }
  207. }
  208. gethostname(hostname, sizeof(hostname));
  209. strcat(hostname, ".local");
  210. host = get_interface(addr);
  211. svr = mdnsd_start(host, verbose);
  212. if (svr) {
  213. printf("host: %s\nidentity: %s\ntype: %s\nip: %s\nport: %u\n", hostname, identity, type, inet_ntoa(host), port);
  214. mdnsd_set_hostname(svr, hostname, host);
  215. svc = mdnsd_register_svc(svr, identity, type, port, NULL, txt);
  216. // mdns_service_destroy(svc);
  217. #ifdef _WIN32
  218. Sleep(INFINITE);
  219. #else
  220. pause();
  221. #endif
  222. mdns_service_remove(svr, svc);
  223. mdnsd_stop(svr);
  224. } else {
  225. printf("Can't start server");
  226. print_usage();
  227. }
  228. free(type);
  229. if (txt) free(txt);
  230. #ifdef _WIN32
  231. winsock_close();
  232. #endif
  233. return 0;
  234. }