Add smbclient support for basic mDNS browsing.
[kai/samba.git] / source3 / client / dnsbrowse.c
diff --git a/source3/client/dnsbrowse.c b/source3/client/dnsbrowse.c
new file mode 100644 (file)
index 0000000..c4819ce
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+   Unix SMB/CIFS implementation.
+   DNS-SD browse client
+   Copyright (C) Rishi Srivatsavai 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef WITH_DNSSD_SUPPORT
+
+#include <dns_sd.h>
+
+/* Holds service instances found during DNS browse */
+struct mdns_smbsrv_result
+{
+       char *serviceName;
+       char *regType;
+       char *domain;
+       uint32_t ifIndex;
+       struct mdns_smbsrv_result *nextResult;
+};
+
+/* Maintains state during DNS browse */
+struct mdns_browse_state
+{
+       struct mdns_smbsrv_result *listhead; /* Browse result list head */
+       int browseDone;
+
+};
+
+
+static void
+do_smb_resolve_reply (DNSServiceRef sdRef, DNSServiceFlags flags,
+               uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+               const char *fullname, const char *hosttarget, uint16_t port,
+               uint16_t txtLen, const unsigned char *txtRecord, void *context)
+{
+       printf("SMB service available on %s port %u\n",
+               hosttarget, ntohs(port));
+}
+
+
+static void do_smb_resolve(struct mdns_smbsrv_result *browsesrv)
+{
+       DNSServiceRef mdns_conn_sdref = NULL;
+       int mdnsfd;
+       int fdsetsz;
+       int ret;
+       fd_set *fdset = NULL;
+       struct timeval tv;
+       DNSServiceErrorType err;
+
+       TALLOC_CTX * ctx = talloc_tos();
+
+       err = DNSServiceResolve(&mdns_conn_sdref, 0 /* flags */,
+               browsesrv->ifIndex,
+               browsesrv->serviceName, browsesrv->regType, browsesrv->domain,
+               do_smb_resolve_reply, NULL);
+
+       if (err != kDNSServiceErr_NoError) {
+               return;
+       }
+
+       mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref);
+       for (;;)  {
+               if (fdset != NULL) {
+                       TALLOC_FREE(fdset);
+               }
+
+               fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
+               fdset = TALLOC_ZERO(ctx, fdsetsz);
+               FD_SET(mdnsfd, fdset);
+
+               tv.tv_sec = 1;
+               tv.tv_usec = 0;
+
+               /* Wait until response received from mDNS daemon */
+               ret = sys_select(mdnsfd + 1, fdset, NULL, NULL, &tv);
+               if (ret <= 0 && errno != EINTR) {
+                       break;
+               }
+
+               if (FD_ISSET(mdnsfd, fdset)) {
+                       /* Invoke callback function */
+                       DNSServiceProcessResult(mdns_conn_sdref);
+                       break;
+               }
+       }
+
+       TALLOC_FREE(fdset);
+       DNSServiceRefDeallocate(mdns_conn_sdref);
+}
+
+
+static void
+do_smb_browse_reply(DNSServiceRef sdRef, DNSServiceFlags flags,
+        uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+        const char  *serviceName, const char *regtype,
+        const char  *replyDomain, void  *context)
+{
+       struct mdns_browse_state *bstatep = (struct mdns_browse_state *)context;
+       struct mdns_smbsrv_result *bresult;
+
+       if (bstatep == NULL) {
+               return;
+       }
+
+       if (errorCode != kDNSServiceErr_NoError) {
+               bstatep->browseDone = 1;
+               return;
+       }
+
+       if (flags & kDNSServiceFlagsMoreComing) {
+               bstatep->browseDone = 0;
+       } else {
+               bstatep->browseDone = 1;
+       }
+
+       if (!(flags & kDNSServiceFlagsAdd)) {
+               return;
+       }
+
+       bresult = TALLOC_ARRAY(talloc_tos(), struct mdns_smbsrv_result, 1);
+       if (bresult == NULL) {
+               return;
+       }
+
+       if (bstatep->listhead != NULL) {
+               bresult->nextResult = bstatep->listhead;
+       }
+
+       bresult->serviceName = talloc_strdup(talloc_tos(), serviceName);
+       bresult->regType = talloc_strdup(talloc_tos(), regtype);
+       bresult->domain = talloc_strdup(talloc_tos(), replyDomain);
+       bresult->ifIndex = interfaceIndex;
+       bstatep->listhead = bresult;
+}
+
+int do_smb_browse(void)
+{
+       int mdnsfd;
+       int fdsetsz;
+       int ret;
+       fd_set *fdset = NULL;
+       struct mdns_browse_state bstate;
+       struct mdns_smbsrv_result *resptr;
+       struct timeval tv;
+       DNSServiceRef mdns_conn_sdref = NULL;
+       DNSServiceErrorType err;
+
+       TALLOC_CTX * ctx = talloc_stackframe();
+
+       ZERO_STRUCT(bstate);
+
+       err = DNSServiceBrowse(&mdns_conn_sdref, 0, 0, "_smb._tcp", "",
+                       do_smb_browse_reply, &bstate);
+
+       if (err != kDNSServiceErr_NoError) {
+               d_printf("Error connecting to the Multicast DNS daemon\n");
+               TALLOC_FREE(ctx);
+               return 1;
+       }
+
+       mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref);
+       for (;;)  {
+               if (fdset != NULL) {
+                       TALLOC_FREE(fdset);
+               }
+
+               fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
+               fdset = TALLOC_ZERO(ctx, fdsetsz);
+               FD_SET(mdnsfd, fdset);
+
+               tv.tv_sec = 1;
+               tv.tv_usec = 0;
+
+               /* Wait until response received from mDNS daemon */
+               ret = sys_select(mdnsfd + 1, fdset, NULL, NULL, &tv);
+               if (ret <= 0 && errno != EINTR) {
+                       break;
+               }
+
+               if (FD_ISSET(mdnsfd, fdset)) {
+                       /* Invoke callback function */
+                       if (DNSServiceProcessResult(mdns_conn_sdref)) {
+                               break;
+                       }
+                       if (bstate.browseDone) {
+                               break;
+                       }
+               }
+       }
+
+       DNSServiceRefDeallocate(mdns_conn_sdref);
+
+       if (bstate.listhead != NULL) {
+               resptr = bstate.listhead;
+               while (resptr != NULL) {
+                       struct mdns_smbsrv_result *oldresptr;
+                       oldresptr = resptr;
+
+                       /* Resolve smb service instance */
+                       do_smb_resolve(resptr);
+
+                       resptr = resptr->nextResult;
+               }
+       }
+
+       TALLOC_FREE(ctx);
+       return 0;
+}
+
+#else /* WITH_DNSSD_SUPPORT */
+
+int do_smb_browse(void)
+{
+    d_printf("DNS-SD browsing is not supported on this platform\n");
+    return 1;
+}
+
+#endif /* WITH_DNSSD_SUPPORT */
+
+