5e3a4de9cff03afb16397a8a6ee03d0579d87326
[sfrench/samba-autobuild/.git] / source3 / client / dnsbrowse.c
1 /*
2    Unix SMB/CIFS implementation.
3    DNS-SD browse client
4    Copyright (C) Rishi Srivatsavai 2007
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "client/client_proto.h"
22
23 #ifdef WITH_DNSSD_SUPPORT
24
25 #include <dns_sd.h>
26
27 /* Holds service instances found during DNS browse */
28 struct mdns_smbsrv_result
29 {
30         char *serviceName;
31         char *regType;
32         char *domain;
33         uint32_t ifIndex;
34         struct mdns_smbsrv_result *nextResult;
35 };
36
37 /* Maintains state during DNS browse */
38 struct mdns_browse_state
39 {
40         struct mdns_smbsrv_result *listhead; /* Browse result list head */
41         int browseDone;
42
43 };
44
45
46 static void
47 do_smb_resolve_reply (DNSServiceRef sdRef, DNSServiceFlags flags,
48                 uint32_t interfaceIndex, DNSServiceErrorType errorCode,
49                 const char *fullname, const char *hosttarget, uint16_t port,
50                 uint16_t txtLen, const unsigned char *txtRecord, void *context)
51 {
52         printf("SMB service available on %s port %u\n",
53                 hosttarget, ntohs(port));
54 }
55
56
57 static void do_smb_resolve(struct mdns_smbsrv_result *browsesrv)
58 {
59         DNSServiceRef mdns_conn_sdref = NULL;
60         int mdnsfd;
61         int fdsetsz;
62         int ret;
63         fd_set *fdset = NULL;
64         struct timeval tv;
65         DNSServiceErrorType err;
66
67         TALLOC_CTX * ctx = talloc_tos();
68
69         err = DNSServiceResolve(&mdns_conn_sdref, 0 /* flags */,
70                 browsesrv->ifIndex,
71                 browsesrv->serviceName, browsesrv->regType, browsesrv->domain,
72                 do_smb_resolve_reply, NULL);
73
74         if (err != kDNSServiceErr_NoError) {
75                 return;
76         }
77
78         mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref);
79         for (;;)  {
80                 if (fdset != NULL) {
81                         TALLOC_FREE(fdset);
82                 }
83
84                 fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
85                 fdset = TALLOC_ZERO(ctx, fdsetsz);
86                 FD_SET(mdnsfd, fdset);
87
88                 tv.tv_sec = 1;
89                 tv.tv_usec = 0;
90
91                 /* Wait until response received from mDNS daemon */
92                 ret = sys_select(mdnsfd + 1, fdset, NULL, NULL, &tv);
93                 if (ret <= 0 && errno != EINTR) {
94                         break;
95                 }
96
97                 if (FD_ISSET(mdnsfd, fdset)) {
98                         /* Invoke callback function */
99                         DNSServiceProcessResult(mdns_conn_sdref);
100                         break;
101                 }
102         }
103
104         TALLOC_FREE(fdset);
105         DNSServiceRefDeallocate(mdns_conn_sdref);
106 }
107
108
109 static void
110 do_smb_browse_reply(DNSServiceRef sdRef, DNSServiceFlags flags,
111         uint32_t interfaceIndex, DNSServiceErrorType errorCode,
112         const char  *serviceName, const char *regtype,
113         const char  *replyDomain, void  *context)
114 {
115         struct mdns_browse_state *bstatep = (struct mdns_browse_state *)context;
116         struct mdns_smbsrv_result *bresult;
117
118         if (bstatep == NULL) {
119                 return;
120         }
121
122         if (errorCode != kDNSServiceErr_NoError) {
123                 bstatep->browseDone = 1;
124                 return;
125         }
126
127         if (flags & kDNSServiceFlagsMoreComing) {
128                 bstatep->browseDone = 0;
129         } else {
130                 bstatep->browseDone = 1;
131         }
132
133         if (!(flags & kDNSServiceFlagsAdd)) {
134                 return;
135         }
136
137         bresult = TALLOC_ARRAY(talloc_tos(), struct mdns_smbsrv_result, 1);
138         if (bresult == NULL) {
139                 return;
140         }
141
142         if (bstatep->listhead != NULL) {
143                 bresult->nextResult = bstatep->listhead;
144         }
145
146         bresult->serviceName = talloc_strdup(talloc_tos(), serviceName);
147         bresult->regType = talloc_strdup(talloc_tos(), regtype);
148         bresult->domain = talloc_strdup(talloc_tos(), replyDomain);
149         bresult->ifIndex = interfaceIndex;
150         bstatep->listhead = bresult;
151 }
152
153 int do_smb_browse(void)
154 {
155         int mdnsfd;
156         int fdsetsz;
157         int ret;
158         fd_set *fdset = NULL;
159         struct mdns_browse_state bstate;
160         struct mdns_smbsrv_result *resptr;
161         struct timeval tv;
162         DNSServiceRef mdns_conn_sdref = NULL;
163         DNSServiceErrorType err;
164
165         TALLOC_CTX * ctx = talloc_stackframe();
166
167         ZERO_STRUCT(bstate);
168
169         err = DNSServiceBrowse(&mdns_conn_sdref, 0, 0, "_smb._tcp", "",
170                         do_smb_browse_reply, &bstate);
171
172         if (err != kDNSServiceErr_NoError) {
173                 d_printf("Error connecting to the Multicast DNS daemon\n");
174                 TALLOC_FREE(ctx);
175                 return 1;
176         }
177
178         mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref);
179         for (;;)  {
180                 if (fdset != NULL) {
181                         TALLOC_FREE(fdset);
182                 }
183
184                 fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
185                 fdset = TALLOC_ZERO(ctx, fdsetsz);
186                 FD_SET(mdnsfd, fdset);
187
188                 tv.tv_sec = 1;
189                 tv.tv_usec = 0;
190
191                 /* Wait until response received from mDNS daemon */
192                 ret = sys_select(mdnsfd + 1, fdset, NULL, NULL, &tv);
193                 if (ret <= 0 && errno != EINTR) {
194                         break;
195                 }
196
197                 if (FD_ISSET(mdnsfd, fdset)) {
198                         /* Invoke callback function */
199                         if (DNSServiceProcessResult(mdns_conn_sdref)) {
200                                 break;
201                         }
202                         if (bstate.browseDone) {
203                                 break;
204                         }
205                 }
206         }
207
208         DNSServiceRefDeallocate(mdns_conn_sdref);
209
210         if (bstate.listhead != NULL) {
211                 resptr = bstate.listhead;
212                 while (resptr != NULL) {
213                         struct mdns_smbsrv_result *oldresptr;
214                         oldresptr = resptr;
215
216                         /* Resolve smb service instance */
217                         do_smb_resolve(resptr);
218
219                         resptr = resptr->nextResult;
220                 }
221         }
222
223         TALLOC_FREE(ctx);
224         return 0;
225 }
226
227 #else /* WITH_DNSSD_SUPPORT */
228
229 int do_smb_browse(void)
230 {
231     d_printf("DNS-SD browsing is not supported on this platform\n");
232     return 1;
233 }
234
235 #endif /* WITH_DNSSD_SUPPORT */
236
237