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 TALLOC_CTX * ctx;
43 int browseDone;
44
45 };
46
47
48 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)49 do_smb_resolve_reply (DNSServiceRef sdRef, DNSServiceFlags flags,
50 uint32_t interfaceIndex, DNSServiceErrorType errorCode,
51 const char *fullname, const char *hosttarget, uint16_t port,
52 uint16_t txtLen, const unsigned char *txtRecord, void *context)
53 {
54 printf("SMB service available on %s port %u\n",
55 hosttarget, ntohs(port));
56 }
57
58
do_smb_resolve(struct mdns_smbsrv_result * browsesrv)59 static void do_smb_resolve(struct mdns_smbsrv_result *browsesrv)
60 {
61 DNSServiceRef mdns_conn_sdref = NULL;
62 int mdnsfd;
63 int fdsetsz;
64 int ret;
65 struct timeval tv;
66 DNSServiceErrorType err;
67
68 TALLOC_CTX * ctx = talloc_new(NULL);
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 int revents;
82
83 ret = poll_one_fd(mdnsfd, POLLIN|POLLHUP, 1000, &revents);
84 if (ret <= 0 && errno != EINTR) {
85 break;
86 }
87
88 if (revents & (POLLIN|POLLHUP|POLLERR)) {
89 /* Invoke callback function */
90 DNSServiceProcessResult(mdns_conn_sdref);
91 break;
92 }
93 }
94
95 TALLOC_FREE(ctx);
96 DNSServiceRefDeallocate(mdns_conn_sdref);
97 }
98
99
100 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)101 do_smb_browse_reply(DNSServiceRef sdRef, DNSServiceFlags flags,
102 uint32_t interfaceIndex, DNSServiceErrorType errorCode,
103 const char *serviceName, const char *regtype,
104 const char *replyDomain, void *context)
105 {
106 struct mdns_browse_state *bstatep = (struct mdns_browse_state *)context;
107 struct mdns_smbsrv_result *bresult;
108
109 if (bstatep == NULL) {
110 return;
111 }
112
113 if (errorCode != kDNSServiceErr_NoError) {
114 bstatep->browseDone = 1;
115 return;
116 }
117
118 if (flags & kDNSServiceFlagsMoreComing) {
119 bstatep->browseDone = 0;
120 } else {
121 bstatep->browseDone = 1;
122 }
123
124 if (!(flags & kDNSServiceFlagsAdd)) {
125 return;
126 }
127
128 bresult = talloc_array(bstatep->ctx, struct mdns_smbsrv_result, 1);
129 if (bresult == NULL) {
130 return;
131 }
132
133 bresult->nextResult = NULL;
134 if (bstatep->listhead != NULL) {
135 bresult->nextResult = bstatep->listhead;
136 }
137
138 bresult->serviceName = talloc_strdup(bstatep->ctx, serviceName);
139 bresult->regType = talloc_strdup(bstatep->ctx, regtype);
140 bresult->domain = talloc_strdup(bstatep->ctx, replyDomain);
141 bresult->ifIndex = interfaceIndex;
142 bstatep->listhead = bresult;
143 }
144
do_smb_browse(void)145 int do_smb_browse(void)
146 {
147 int mdnsfd;
148 int fdsetsz;
149 int ret;
150 struct mdns_browse_state bstate;
151 struct mdns_smbsrv_result *resptr;
152 struct timeval tv;
153 DNSServiceRef mdns_conn_sdref = NULL;
154 DNSServiceErrorType err;
155
156 TALLOC_CTX * ctx = talloc_new(NULL);
157
158 ZERO_STRUCT(bstate);
159
160 bstate.ctx = ctx;
161 bstate.listhead = NULL;
162
163 err = DNSServiceBrowse(&mdns_conn_sdref, 0, 0, "_smb._tcp", "",
164 do_smb_browse_reply, &bstate);
165
166 if (err != kDNSServiceErr_NoError) {
167 d_printf("Error connecting to the Multicast DNS daemon\n");
168 TALLOC_FREE(ctx);
169 return 1;
170 }
171
172 mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref);
173 for (;;) {
174 int revents;
175
176 ret = poll_one_fd(mdnsfd, POLLIN|POLLHUP, 1000, &revents);
177 if (ret <= 0 && errno != EINTR) {
178 break;
179 }
180
181 if (revents & (POLLIN|POLLHUP|POLLERR)) {
182 /* Invoke callback function */
183 if (DNSServiceProcessResult(mdns_conn_sdref)) {
184 break;
185 }
186 if (bstate.browseDone) {
187 break;
188 }
189 }
190 }
191
192 DNSServiceRefDeallocate(mdns_conn_sdref);
193
194 if (bstate.listhead != NULL) {
195 resptr = bstate.listhead;
196 while (resptr != NULL) {
197 struct mdns_smbsrv_result *oldresptr;
198 oldresptr = resptr;
199
200 /* Resolve smb service instance */
201 do_smb_resolve(resptr);
202
203 resptr = resptr->nextResult;
204 }
205 }
206
207 TALLOC_FREE(ctx);
208 return 0;
209 }
210
211 #else /* WITH_DNSSD_SUPPORT */
212
do_smb_browse(void)213 int do_smb_browse(void)
214 {
215 d_printf("DNS-SD browsing is not supported on this platform\n");
216 return 1;
217 }
218
219 #endif /* WITH_DNSSD_SUPPORT */
220
221
222