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