/* * tinysvcmdns - a tiny MDNS implementation for publishing services * Copyright (C) 2011 Darell Tan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #ifdef _WIN32 #include #include #include typedef uint32_t in_addr_t; #elif defined (linux) || defined (__FreeBSD__) #include #include #include #include #include #include #if defined (__FreeBSD__) #include #include #include #endif #elif defined (__APPLE__) #include #include #include #include #include #include #include #endif #include "mdns.h" #include "mdnsd.h" struct mdns_service *svc; struct mdnsd *svr; /*---------------------------------------------------------------------------*/ #ifdef WIN32 static void winsock_init(void) { WSADATA wsaData; WORD wVersionRequested = MAKEWORD(2, 2); int WSerr = WSAStartup(wVersionRequested, &wsaData); if (WSerr != 0) exit(1); } /*---------------------------------------------------------------------------*/ static void winsock_close(void) { WSACleanup(); } #endif /*---------------------------------------------------------------------------*/ #define MAX_INTERFACES 256 #define DEFAULT_INTERFACE 1 #if !defined(WIN32) #define INVALID_SOCKET (-1) #endif static in_addr_t get_localhost(char **name) { #ifdef WIN32 char buf[256]; struct hostent *h = NULL; struct sockaddr_in LocalAddr; memset(&LocalAddr, 0, sizeof(LocalAddr)); gethostname(buf, 256); h = gethostbyname(buf); if (name) *name = strdup(buf); if (h != NULL) { memcpy(&LocalAddr.sin_addr, h->h_addr_list[0], 4); return LocalAddr.sin_addr.s_addr; } else return INADDR_ANY; #elif defined (__APPLE__) || defined(__FreeBSD__) struct ifaddrs *ifap, *ifa; if (name) { *name = malloc(256); gethostname(*name, 256); } if (getifaddrs(&ifap) != 0) return INADDR_ANY; /* cycle through available interfaces */ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { /* Skip loopback, point-to-point and down interfaces, * except don't skip down interfaces * if we're trying to get a list of configurable interfaces. */ if ((ifa->ifa_flags & IFF_LOOPBACK) || (!( ifa->ifa_flags & IFF_UP))) { continue; } if (ifa->ifa_addr->sa_family == AF_INET) { /* We don't want the loopback interface. */ if (((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { continue; } return ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr; break; } } freeifaddrs(ifap); return INADDR_ANY; #else char szBuffer[MAX_INTERFACES * sizeof (struct ifreq)]; struct ifconf ifConf; struct ifreq ifReq; int nResult; long unsigned int i; int LocalSock; struct sockaddr_in LocalAddr; int j = 0; if (name) { *name = malloc(256); gethostname(*name, 256); } /* purify */ memset(&ifConf, 0, sizeof(ifConf)); memset(&ifReq, 0, sizeof(ifReq)); memset(szBuffer, 0, sizeof(szBuffer)); memset(&LocalAddr, 0, sizeof(LocalAddr)); /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */ LocalSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (LocalSock == INVALID_SOCKET) return false; /* Get the interface configuration information... */ ifConf.ifc_len = (int)sizeof szBuffer; ifConf.ifc_ifcu.ifcu_buf = (caddr_t) szBuffer; nResult = ioctl(LocalSock, SIOCGIFCONF, &ifConf); if (nResult < 0) { close(LocalSock); return INADDR_ANY; } /* Cycle through the list of interfaces looking for IP addresses. */ for (i = 0lu; i < (long unsigned int)ifConf.ifc_len && j < DEFAULT_INTERFACE; ) { struct ifreq *pifReq = (struct ifreq *)((caddr_t)ifConf.ifc_req + i); i += sizeof *pifReq; /* See if this is the sort of interface we want to deal with. */ memset(ifReq.ifr_name, 0, sizeof(ifReq.ifr_name)); strncpy(ifReq.ifr_name, pifReq->ifr_name, sizeof(ifReq.ifr_name) - 1); /* Skip loopback, point-to-point and down interfaces, * except don't skip down interfaces * if we're trying to get a list of configurable interfaces. */ ioctl(LocalSock, SIOCGIFFLAGS, &ifReq); if ((ifReq.ifr_flags & IFF_LOOPBACK) || (!(ifReq.ifr_flags & IFF_UP))) { continue; } if (pifReq->ifr_addr.sa_family == AF_INET) { /* Get a pointer to the address...*/ memcpy(&LocalAddr, &pifReq->ifr_addr, sizeof pifReq->ifr_addr); /* We don't want the loopback interface. */ if (LocalAddr.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { continue; } } /* increment j if we found an address which is not loopback * and is up */ j++; } close(LocalSock); return LocalAddr.sin_addr.s_addr; #endif } /*---------------------------------------------------------------------------*/ static int print_usage(void) { printf(" [txt] ... [txt]\n"); #ifdef WIN32 winsock_close(); #endif return 1; } /*---------------------------------------------------------------------------*/ static void sighandler(int signum) { mdnsd_stop(svr); #ifdef WIN32 winsock_close(); #endif exit(0); } /*---------------------------------------------------------------------------*/ /* */ /*---------------------------------------------------------------------------*/ #ifdef MDNS_SVC int mdns_server(int argc, char *argv[]) { #else int main(int argc, char *argv[]) { #endif char type[255]; int port; const char **txt; struct in_addr host; char *hostname; signal(SIGINT, sighandler); signal(SIGTERM, sighandler); #if defined(SIGPIPE) signal(SIGPIPE, SIG_IGN); #endif #if defined(SIGQUIT) signal(SIGQUIT, sighandler); #endif #if defined(SIGHUP) signal(SIGHUP, sighandler); #endif #ifdef WIN32 winsock_init(); #endif if (argc < 5) return print_usage(); port = atoi(argv[3]); host.s_addr = get_localhost(&hostname); hostname = realloc(hostname, strlen(hostname) + strlen(".local")); strcat(hostname, ".local"); if (host.s_addr == INADDR_ANY) { printf("cannot find host address\n"); free(hostname); return print_usage(); } svr = mdnsd_start(host); if (svr == NULL) return print_usage(); txt = malloc((argc - 4 + 1) * sizeof(char**)); memcpy(txt, argv + 4, (argc - 4) * sizeof(char**)); txt[argc + 4] = NULL; mdnsd_set_hostname(svr, hostname, host); free(hostname); sprintf(type, "%s.local", argv[2]); printf("host : %s\nidentity : %s\ntype : %s\n" "ip : %s\nport : %u\n", hostname, argv[1], type, inet_ntoa(host), port); svc = mdnsd_register_svc(svr, argv[1], type, port, NULL, txt); mdns_service_destroy(svc); #ifdef WIN32 Sleep(INFINITE); #else pause(); #endif mdnsd_stop(svr); #ifdef WIN32 winsock_close(); #endif return 0; }