2 * Unix SMB/CIFS implementation.
3 * Register _smb._tcp with avahi
5 * Copyright (C) Volker Lendecke 2009
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "smbd/smbd.h"
24 #include <avahi-client/client.h>
25 #include <avahi-client/publish.h>
26 #include <avahi-common/error.h>
27 #include <avahi-common/malloc.h>
28 #include <avahi-common/strlst.h>
30 struct avahi_state_struct
{
31 struct AvahiPoll
*poll
;
33 AvahiEntryGroup
*entry_group
;
37 static void *avahi_allocator_ctx
= NULL
;
39 static void * avahi_allocator_malloc(size_t size
)
41 return talloc_size(avahi_allocator_ctx
, size
);
44 static void avahi_allocator_free(void *p
)
49 static void * avahi_allocator_realloc(void *p
, size_t size
)
51 return talloc_realloc_size(avahi_allocator_ctx
, p
, size
);
54 static void * avahi_allocator_calloc(size_t count
, size_t size
)
56 void *p
= talloc_array_size(avahi_allocator_ctx
, size
, count
);
58 memset(p
, 0, size
* count
);
63 static const struct AvahiAllocator avahi_talloc_allocator
= {
64 &avahi_allocator_malloc
,
65 &avahi_allocator_free
,
66 &avahi_allocator_realloc
,
67 &avahi_allocator_calloc
70 static void avahi_entry_group_callback(AvahiEntryGroup
*g
,
71 AvahiEntryGroupState status
,
74 struct avahi_state_struct
*state
= talloc_get_type_abort(
75 userdata
, struct avahi_state_struct
);
79 case AVAHI_ENTRY_GROUP_ESTABLISHED
:
80 DBG_DEBUG("AVAHI_ENTRY_GROUP_ESTABLISHED\n");
82 case AVAHI_ENTRY_GROUP_FAILURE
:
83 error
= avahi_client_errno(state
->client
);
85 DBG_DEBUG("AVAHI_ENTRY_GROUP_FAILURE: %s\n",
86 avahi_strerror(error
));
88 case AVAHI_ENTRY_GROUP_COLLISION
:
89 DBG_DEBUG("AVAHI_ENTRY_GROUP_COLLISION\n");
91 case AVAHI_ENTRY_GROUP_UNCOMMITED
:
92 DBG_DEBUG("AVAHI_ENTRY_GROUP_UNCOMMITED\n");
94 case AVAHI_ENTRY_GROUP_REGISTERING
:
95 DBG_DEBUG("AVAHI_ENTRY_GROUP_REGISTERING\n");
100 static void avahi_client_callback(AvahiClient
*c
, AvahiClientState status
,
103 struct avahi_state_struct
*state
= talloc_get_type_abort(
104 userdata
, struct avahi_state_struct
);
108 case AVAHI_CLIENT_S_RUNNING
: {
110 int num_services
= lp_numservices();
112 AvahiStringList
*adisk
= NULL
;
113 AvahiStringList
*adisk2
= NULL
;
114 AvahiStringList
*dinfo
= NULL
;
115 const char *hostname
= NULL
;
116 enum mdns_name_values mdns_name
= lp_mdns_name();
117 const char *model
= NULL
;
119 DBG_DEBUG("AVAHI_CLIENT_S_RUNNING\n");
123 hostname
= avahi_client_get_host_name(c
);
125 case MDNS_NAME_NETBIOS
:
126 hostname
= lp_netbios_name();
129 DBG_ERR("Unhandled mdns_name %d\n", mdns_name
);
133 state
->entry_group
= avahi_entry_group_new(
134 c
, avahi_entry_group_callback
, state
);
135 if (state
->entry_group
== NULL
) {
136 error
= avahi_client_errno(c
);
137 DBG_DEBUG("avahi_entry_group_new failed: %s\n",
138 avahi_strerror(error
));
142 error
= avahi_entry_group_add_service(
143 state
->entry_group
, AVAHI_IF_UNSPEC
,
144 AVAHI_PROTO_UNSPEC
, 0, hostname
,
145 "_smb._tcp", NULL
, NULL
, state
->port
, NULL
);
146 if (error
!= AVAHI_OK
) {
147 DBG_DEBUG("avahi_entry_group_add_service failed: %s\n",
148 avahi_strerror(error
));
149 avahi_entry_group_free(state
->entry_group
);
150 state
->entry_group
= NULL
;
154 for (snum
= 0; snum
< num_services
; snum
++) {
155 if (lp_snum_ok(snum
) &&
156 lp_parm_bool(snum
, "fruit", "time machine", false))
158 adisk2
= avahi_string_list_add_printf(
159 adisk
, "dk%zu=adVN=%s,adVF=0x82",
160 dk
++, lp_const_servicename(snum
));
161 if (adisk2
== NULL
) {
162 DBG_DEBUG("avahi_string_list_add_printf"
163 "failed: returned NULL\n");
164 avahi_string_list_free(adisk
);
165 avahi_entry_group_free(state
->entry_group
);
166 state
->entry_group
= NULL
;
174 adisk2
= avahi_string_list_add(adisk
, "sys=adVF=0x100");
175 if (adisk2
== NULL
) {
176 DBG_DEBUG("avahi_string_list_add failed: "
178 avahi_string_list_free(adisk
);
179 avahi_entry_group_free(state
->entry_group
);
180 state
->entry_group
= NULL
;
186 error
= avahi_entry_group_add_service_strlst(
187 state
->entry_group
, AVAHI_IF_UNSPEC
,
188 AVAHI_PROTO_UNSPEC
, 0, hostname
,
189 "_adisk._tcp", NULL
, NULL
, 0, adisk
);
190 avahi_string_list_free(adisk
);
192 if (error
!= AVAHI_OK
) {
193 DBG_DEBUG("avahi_entry_group_add_service_strlst "
194 "failed: %s\n", avahi_strerror(error
));
195 avahi_entry_group_free(state
->entry_group
);
196 state
->entry_group
= NULL
;
201 model
= lp_parm_const_string(-1, "fruit", "model", "MacSamba");
203 dinfo
= avahi_string_list_add_printf(NULL
, "model=%s", model
);
205 DBG_DEBUG("avahi_string_list_add_printf"
206 "failed: returned NULL\n");
207 avahi_entry_group_free(state
->entry_group
);
208 state
->entry_group
= NULL
;
212 error
= avahi_entry_group_add_service_strlst(
213 state
->entry_group
, AVAHI_IF_UNSPEC
,
214 AVAHI_PROTO_UNSPEC
, 0, hostname
,
215 "_device-info._tcp", NULL
, NULL
, 0,
217 avahi_string_list_free(dinfo
);
218 if (error
!= AVAHI_OK
) {
219 DBG_DEBUG("avahi_entry_group_add_service failed: %s\n",
220 avahi_strerror(error
));
221 avahi_entry_group_free(state
->entry_group
);
222 state
->entry_group
= NULL
;
226 error
= avahi_entry_group_commit(state
->entry_group
);
227 if (error
!= AVAHI_OK
) {
228 DBG_DEBUG("avahi_entry_group_commit failed: %s\n",
229 avahi_strerror(error
));
230 avahi_entry_group_free(state
->entry_group
);
231 state
->entry_group
= NULL
;
236 case AVAHI_CLIENT_FAILURE
:
237 error
= avahi_client_errno(c
);
239 DBG_DEBUG("AVAHI_CLIENT_FAILURE: %s\n", avahi_strerror(error
));
241 if (error
!= AVAHI_ERR_DISCONNECTED
) {
244 avahi_client_free(c
);
245 state
->client
= avahi_client_new(state
->poll
, AVAHI_CLIENT_NO_FAIL
,
246 avahi_client_callback
, state
,
248 if (state
->client
== NULL
) {
249 DBG_DEBUG("avahi_client_new failed: %s\n",
250 avahi_strerror(error
));
254 case AVAHI_CLIENT_S_COLLISION
:
255 DBG_DEBUG("AVAHI_CLIENT_S_COLLISION\n");
257 case AVAHI_CLIENT_S_REGISTERING
:
258 DBG_DEBUG("AVAHI_CLIENT_S_REGISTERING\n");
260 case AVAHI_CLIENT_CONNECTING
:
261 DBG_DEBUG("AVAHI_CLIENT_CONNECTING\n");
266 void *avahi_start_register(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
269 struct avahi_state_struct
*state
;
272 avahi_allocator_ctx
= talloc_new(mem_ctx
);
273 if (avahi_allocator_ctx
== NULL
) {
276 avahi_set_allocator(&avahi_talloc_allocator
);
278 state
= talloc(mem_ctx
, struct avahi_state_struct
);
283 state
->poll
= tevent_avahi_poll(state
, ev
);
284 if (state
->poll
== NULL
) {
287 state
->client
= avahi_client_new(state
->poll
, AVAHI_CLIENT_NO_FAIL
,
288 avahi_client_callback
, state
,
290 if (state
->client
== NULL
) {
291 DBG_DEBUG("avahi_client_new failed: %s\n",
292 avahi_strerror(error
));