The following patch adds support for service discovery in samba. Changes are in smbd and smbclient components. This support will be turned on for Samba in Solaris. Changes to autoconf for this feature is not included in the patch below. But I hope to include it as well. Index: smbd/server.c =================================================================== --- smbd/server.c (revision 21843) +++ smbd/server.c (working copy) @@ -296,6 +296,120 @@ return num_children < max_processes; } + +#ifdef HAVE_LIBDNS_SD + +/* Uses DNS service discovery (libdns_sd) to + * register the SMB service. SMB service is registered + * on ".local" domain via Multicast DNS & any + * other unicast DNS domains available. + * + * Users use the smbclient -B (Browse) option to + * browse for advertised SMB services. + */ + + +static void dns_register_close(struct dns_reg_state *regstateptr) +{ + int mdnsd_conn_fd; + + if (regstateptr == NULL) + return; + + if (regstateptr->regsrvref != NULL) { + /* Close connection to the mDNS daemon */ + DNSServiceRefDeallocate(regstateptr->regsrvref); + regstateptr->regsrvref = NULL; + } + + /* Clear event handler */ + if (regstateptr->dnsregretryhandler != NULL) { + TALLOC_FREE(regstateptr->dnsregretryhandler); + regstateptr->dnsregretryhandler = NULL; + } +} + + +static void dns_register_smbd_retry(struct event_context *ctx, + struct timed_event *te, + const struct timeval *now, + void *private_data) +{ + struct dns_reg_state *regstateptr = (struct dns_reg_state *)private_data; + /* Clear previous registration state to force new + * registration attempt. Clears event handler. */ + dns_register_close(regstateptr); +} + +static void schedule_dns_register_smbd_retry(struct dns_reg_state *regstateptr) +{ + regstateptr->regsrvref = NULL; + regstateptr->dnsregretryhandler = event_add_timed( + smbd_event_context(), + NULL, timeval_current_ofs(DNS_REG_RETRY_INTERVAL, 0), + "DNS registration handler", + dns_register_smbd_retry, regstateptr); +} + + + +static void dns_register_smbd(struct dns_reg_state *regstateptr, int *maxfd, fd_set *listen_set) +{ + int mdnsd_conn_fd; + + /* Quit if a re-try attempt has been scheduled. */ + if (regstateptr->dnsregretryhandler != NULL) + return; + + /* If a registration is active add conn + * fd to select listen_set and return */ + if (regstateptr->regsrvref != NULL) { + mdnsd_conn_fd = DNSServiceRefSockFD(regstateptr->regsrvref); + FD_SET(mdnsd_conn_fd, listen_set); + return; + } + + /* Register service with DNS. Connects with the mDNS + * daemon running on the local system to perform DNS + * service registration. + */ + if (!DNSServiceRegister(®stateptr->regsrvref, 0, + kDNSServiceInterfaceIndexAny, "", "_smb._tcp", "", "", + htons(139), 0, NULL, NULL, NULL)) { + mdnsd_conn_fd = DNSServiceRefSockFD(regstateptr->regsrvref); + FD_SET(mdnsd_conn_fd, listen_set); + *maxfd = MAX(*maxfd, mdnsd_conn_fd); + } else { + /* Failed to register service. Schedule a re-try attempt. + */ + DEBUG(3,("dns_sd: could not register with mDNS daemon.\n")); + schedule_dns_register_smbd_retry(regstateptr); + } +} + +/* Processes reply from mDNS daemon. Returns True if a reply was received */ +static BOOL dns_register_smbd_reply(struct dns_reg_state *regstateptr, fd_set *lfds) +{ + int mdnsd_conn_fd = -1; + + if (regstateptr->regsrvref != NULL) { + mdnsd_conn_fd = DNSServiceRefSockFD(regstateptr->regsrvref); + /* Process reply from daemon. Handles any errors. */ + if( (mdnsd_conn_fd != -1) && (FD_ISSET(mdnsd_conn_fd, lfds)) ) { + if ( DNSServiceProcessResult(regstateptr->regsrvref) != kDNSServiceErr_NoError) { + DEBUG(3,("dns_sd: mdns process result returned error. Keep re-trying.\n")); + schedule_dns_register_smbd_retry(regstateptr); + } + return True; + } + } + return False; +} + +#endif /* HAVE_LIBDNS_SD */ + + + /**************************************************************************** Open the socket communication. ****************************************************************************/ @@ -311,6 +425,11 @@ int i; char *ports; +#ifdef HAVE_LIBDNS_SD + struct dns_reg_state dnsregptr; + (void) memset(&dnsregptr, 0, sizeof(struct dns_reg_state)); +#endif + if (!is_daemon) { return open_sockets_inetd(); } @@ -459,6 +578,7 @@ while (1) { fd_set lfds; int num; + struct timeval tmo; /* Free up temporary memory from the main smbd. */ lp_TALLOC_FREE(); @@ -477,9 +597,16 @@ memcpy((char *)&lfds, (char *)&listen_set, sizeof(listen_set)); + +#ifdef HAVE_LIBDNS_SD + dns_register_smbd(&dnsregptr, &maxfd, &lfds); +#endif + + if (get_timed_events_timeout(smbd_event_context(), &tmo) != NULL) + num = sys_select(maxfd+1,&lfds,NULL,NULL,&tmo); + else + num = sys_select(maxfd+1,&lfds,NULL,NULL,NULL); - num = sys_select(maxfd+1,&lfds,NULL,NULL,NULL); - if (num == -1 && errno == EINTR) { if (got_sig_term) { exit_server_cleanly(NULL); @@ -495,7 +622,15 @@ continue; } - + +#ifdef HAVE_LIBDNS_SD + if (dns_register_smbd_reply(&dnsregptr, &lfds) && ((--num) == 0)) + continue; +#endif + + /* Process expired events */ + run_events(smbd_event_context(), 0, NULL, NULL); + /* check if we need to reload services */ check_reload(time(NULL)); @@ -546,6 +681,11 @@ /* close the listening socket(s) */ for(i = 0; i < num_sockets; i++) close(fd_listenset[i]); + +#ifdef HAVE_LIBDNS_SD + /* close socket to mDNS daemon */ + dns_register_close(&dnsregptr); +#endif /* close our standard file descriptors */ Index: include/includes.h =================================================================== --- include/includes.h (revision 21843) +++ include/includes.h (working copy) @@ -1234,4 +1234,13 @@ #include "libnscd.h" #endif +#ifdef HAVE_LIBDNS_SD +#include "dns_sd.h" +#define DNS_REG_RETRY_INTERVAL 5*60 /* in seconds */ +struct dns_reg_state { + DNSServiceRef regsrvref; + struct timed_event *dnsregretryhandler; +}; +#endif /* HAVE_LIBDNS_SD */ + #endif /* _INCLUDES_H */ Index: client/client.c =================================================================== --- client/client.c (revision 21843) - Hide quoted text - +++ client/client.c (working copy) @@ -3863,6 +3863,9 @@ { "send-buffer", 'b', POPT_ARG_INT, &io_bufsize, 'b', "Changes the transmit/send buffer", "BYTES" }, { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" }, { "grepable", 'g', POPT_ARG_NONE, NULL, 'g', "Produce grepable output" }, +#ifdef HAVE_LIBDNS_SD + { "browse", 'B', POPT_ARG_NONE, NULL, 'B', "Browse SMB servers using DNS" }, +#endif /*HAVE_LIBDNS_SD */ POPT_COMMON_SAMBA POPT_COMMON_CONNECTION POPT_COMMON_CREDENTIALS @@ -3968,6 +3971,11 @@ case 'g': grepable=True; break; +#ifdef HAVE_LIBDNS_SD + case 'B': + return(do_smb_browse()); +#endif /* HAVE_LIBDNS_SD */ + } } Index: client/dnsbrowse.c =================================================================== --- client/dnsbrowse.c (revision 0) +++ client/dnsbrowse.c (revision 0) @@ -0,0 +1,214 @@ +/* + Unix SMB/CIFS implementation. + SMB client + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +#ifdef HAVE_LIBDNS_SD + +/* 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\n", hosttarget); +} + + +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; + + if(DNSServiceResolve(&mdns_conn_sdref, NULL, browsesrv->ifIndex, + browsesrv->serviceName, browsesrv->regType, browsesrv->domain, + do_smb_resolve_reply, NULL) != kDNSServiceErr_NoError) + return; + + mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref); + for (;;) { + if (fdset != NULL) + free(fdset); + + fdsetsz = howmany(mdnsfd+1, NFDBITS) * sizeof(fd_mask); + fdset = (fd_set *)malloc(fdsetsz); + (void) memset(fdset, 0, fdsetsz); + FD_SET(mdnsfd, fdset); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + /* Wait until response received from mDNS daemon */ + ret = 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; + } + } + + 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 = (struct mdns_smbsrv_result *)calloc(1, sizeof(struct mdns_smbsrv_result)); + if (bresult == NULL) + return; + + if (bstatep->listhead != NULL) + bresult->nextResult = bstatep->listhead; + bresult->serviceName = strdup(serviceName); + bresult->regType = strdup(regtype); + bresult->domain = strdup(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; + + (void) memset(&bstate, 0, sizeof(struct mdns_browse_state)); + + if(DNSServiceBrowse(&mdns_conn_sdref, 0, 0, "_smb._tcp", "", + do_smb_browse_reply, &bstate) != kDNSServiceErr_NoError) + { + d_printf("Error connecting to the Multicast DNS daemon\n"); + return 1; + } + + mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref); + for (;;) { + if (fdset != NULL) + free(fdset); + + fdsetsz = howmany(mdnsfd+1, NFDBITS) * sizeof(fd_mask); + fdset = (fd_set *)malloc(fdsetsz); + (void) memset(fdset, 0, fdsetsz); + FD_SET(mdnsfd, fdset); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + /* Wait until response received from mDNS daemon */ + ret = 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; + } + } + + free(fdset); + 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); + + /* Free result structure */ + free(resptr->domain); + free(resptr->serviceName); + free(resptr->regType); + resptr = resptr->nextResult; + free(oldresptr); + } + } + return 0; +} + +#endif /* HAVE_LIBDNS_SD */
Rishi, Please include the patch as an attachment and not inline. Thanks.
Reviewing for 3.0.26.
Created attachment 2391 [details] PATCH for service discovery support in samba via DNS Proposed patch for DNS service discovery support in Samba.
Created attachment 2859 [details] PATCH for service discovery support in samba via DNS Updated patch. Added configure option with-dnssd and synced patch to revision 24280
Jerry, you can assign this to me if you like. I can build and test on Mac. Rishi, this patch needs copyright attributions for all the files that have substantive changes, as per the Samba copyright policy: http://us1.samba.org/samba/devel/copyright-policy.html thanks
Thanks James.
Created attachment 2934 [details] service discovery support via DNS
Merged service registration as <http://git.samba.org/?p=samba.git;a=commit;h=1e7241517d1f55d60af22570e0c9feb280e3fdb5>
Merged smbclient support: <http://git.samba.org/?p=samba.git;a=commit;h=db74b99d0ef1a60894c838b4c9d0d454db6cf620>
All merged, thanks a lot for the patch.