diff options
Diffstat (limited to 'source3/client/dnsbrowse.c')
-rw-r--r-- | source3/client/dnsbrowse.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/source3/client/dnsbrowse.c b/source3/client/dnsbrowse.c new file mode 100644 index 0000000000..c4819cebfa --- /dev/null +++ b/source3/client/dnsbrowse.c @@ -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 */ + + |