s3: Eliminate sys_select from do_smb_browse() -- untested
[samba.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 #include "system/select.h"
27
28 /* Holds service instances found during DNS browse */
29 struct mdns_smbsrv_result
30 {
31         char *serviceName;
32         char *regType;
33         char *domain;
34         uint32_t ifIndex;
35         struct mdns_smbsrv_result *nextResult;
36 };
37
38 /* Maintains state during DNS browse */
39 struct mdns_browse_state
40 {
41         struct mdns_smbsrv_result *listhead; /* Browse result list head */
42         int browseDone;
43
44 };
45
46
47 static void
48 do_smb_resolve_reply (DNSServiceRef sdRef, DNSServiceFlags flags,
49                 uint32_t interfaceIndex, DNSServiceErrorType errorCode,
50                 const char *fullname, const char *hosttarget, uint16_t port,
51                 uint16_t txtLen, const unsigned char *txtRecord, void *context)
52 {
53         printf("SMB service available on %s port %u\n",
54                 hosttarget, ntohs(port));
55 }
56
57
58 static void do_smb_resolve(struct mdns_smbsrv_result *browsesrv)
59 {
60         DNSServiceRef mdns_conn_sdref = NULL;
61         int mdnsfd;
62         int fdsetsz;
63         int ret;
64         fd_set *fdset = NULL;
65         struct timeval tv;
66         DNSServiceErrorType err;
67
68         TALLOC_CTX * ctx = talloc_tos();
69
70         err = DNSServiceResolve(&mdns_conn_sdref, 0 /* flags */,
71                 browsesrv->ifIndex,
72                 browsesrv->serviceName, browsesrv->regType, browsesrv->domain,
73                 do_smb_resolve_reply, NULL);
74
75         if (err != kDNSServiceErr_NoError) {
76                 return;
77         }
78
79         mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref);
80         for (;;)  {
81                 if (fdset != NULL) {
82                         TALLOC_FREE(fdset);
83                 }
84
85                 fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
86                 fdset = TALLOC_ZERO(ctx, fdsetsz);
87                 FD_SET(mdnsfd, fdset);
88
89                 tv.tv_sec = 1;
90                 tv.tv_usec = 0;
91
92                 /* Wait until response received from mDNS daemon */
93                 ret = sys_select(mdnsfd + 1, fdset, NULL, NULL, &tv);
94                 if (ret <= 0 && errno != EINTR) {
95                         break;
96                 }
97
98                 if (FD_ISSET(mdnsfd, fdset)) {
99                         /* Invoke callback function */
100                         DNSServiceProcessResult(mdns_conn_sdref);
101                         break;
102                 }
103         }
104
105         TALLOC_FREE(fdset);
106         DNSServiceRefDeallocate(mdns_conn_sdref);
107 }
108
109
110 static void
111 do_smb_browse_reply(DNSServiceRef sdRef, DNSServiceFlags flags,
112         uint32_t interfaceIndex, DNSServiceErrorType errorCode,
113         const char  *serviceName, const char *regtype,
114         const char  *replyDomain, void  *context)
115 {
116         struct mdns_browse_state *bstatep = (struct mdns_browse_state *)context;
117         struct mdns_smbsrv_result *bresult;
118
119         if (bstatep == NULL) {
120                 return;
121         }
122
123         if (errorCode != kDNSServiceErr_NoError) {
124                 bstatep->browseDone = 1;
125                 return;
126         }
127
128         if (flags & kDNSServiceFlagsMoreComing) {
129                 bstatep->browseDone = 0;
130         } else {
131                 bstatep->browseDone = 1;
132         }
133
134         if (!(flags & kDNSServiceFlagsAdd)) {
135                 return;
136         }
137
138         bresult = TALLOC_ARRAY(talloc_tos(), struct mdns_smbsrv_result, 1);
139         if (bresult == NULL) {
140                 return;
141         }
142
143         if (bstatep->listhead != NULL) {
144                 bresult->nextResult = bstatep->listhead;
145         }
146
147         bresult->serviceName = talloc_strdup(talloc_tos(), serviceName);
148         bresult->regType = talloc_strdup(talloc_tos(), regtype);
149         bresult->domain = talloc_strdup(talloc_tos(), replyDomain);
150         bresult->ifIndex = interfaceIndex;
151         bstatep->listhead = bresult;
152 }
153
154 int do_smb_browse(void)
155 {
156         int mdnsfd;
157         int fdsetsz;
158         int ret;
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                 int revents;
181
182                 ret = poll_one_fd(mdnsfd, POLLIN|POLLHUP, &revents, 1000);
183                 if (ret <= 0 && errno != EINTR) {
184                         break;
185                 }
186
187                 if (revents & (POLLIN|POLLHUP|POLLERR)) {
188                         /* Invoke callback function */
189                         if (DNSServiceProcessResult(mdns_conn_sdref)) {
190                                 break;
191                         }
192                         if (bstate.browseDone) {
193                                 break;
194                         }
195                 }
196         }
197
198         DNSServiceRefDeallocate(mdns_conn_sdref);
199
200         if (bstate.listhead != NULL) {
201                 resptr = bstate.listhead;
202                 while (resptr != NULL) {
203                         struct mdns_smbsrv_result *oldresptr;
204                         oldresptr = resptr;
205
206                         /* Resolve smb service instance */
207                         do_smb_resolve(resptr);
208
209                         resptr = resptr->nextResult;
210                 }
211         }
212
213         TALLOC_FREE(ctx);
214         return 0;
215 }
216
217 #else /* WITH_DNSSD_SUPPORT */
218
219 int do_smb_browse(void)
220 {
221     d_printf("DNS-SD browsing is not supported on this platform\n");
222     return 1;
223 }
224
225 #endif /* WITH_DNSSD_SUPPORT */
226
227