2007-12-18 09:09:09 +03:00
/*
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"
2007-12-19 22:27:47 +03:00
# include "client/client_proto.h"
2007-12-18 09:09:09 +03:00
# 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 */