/*
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 .
*/
#include "includes.h"
#ifdef WITH_DNSSD_SUPPORT
#include
/* 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 */