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 const char *hostname
= NULL
;
115 enum mdns_name_values mdns_name
= lp_mdns_name();
117 DBG_DEBUG("AVAHI_CLIENT_S_RUNNING\n");
121 hostname
= avahi_client_get_host_name(c
);
123 case MDNS_NAME_NETBIOS
:
124 hostname
= lp_netbios_name();
127 DBG_ERR("Unhandled mdns_name %d\n", mdns_name
);
131 state
->entry_group
= avahi_entry_group_new(
132 c
, avahi_entry_group_callback
, state
);
133 if (state
->entry_group
== NULL
) {
134 error
= avahi_client_errno(c
);
135 DBG_DEBUG("avahi_entry_group_new failed: %s\n",
136 avahi_strerror(error
));
140 error
= avahi_entry_group_add_service(
141 state
->entry_group
, AVAHI_IF_UNSPEC
,
142 AVAHI_PROTO_UNSPEC
, 0, hostname
,
143 "_smb._tcp", NULL
, NULL
, state
->port
, NULL
);
144 if (error
!= AVAHI_OK
) {
145 DBG_DEBUG("avahi_entry_group_add_service failed: %s\n",
146 avahi_strerror(error
));
147 avahi_entry_group_free(state
->entry_group
);
148 state
->entry_group
= NULL
;
152 for (snum
= 0; snum
< num_services
; snum
++) {
153 if (lp_snum_ok(snum
) &&
154 lp_parm_bool(snum
, "fruit", "time machine", false))
156 adisk2
= avahi_string_list_add_printf(
157 adisk
, "dk%d=adVN=%s,adVF=0x82",
158 dk
++, lp_const_servicename(snum
));
159 if (adisk2
== NULL
) {
160 DBG_DEBUG("avahi_string_list_add_printf"
161 "failed: returned NULL\n");
162 avahi_string_list_free(adisk
);
163 avahi_entry_group_free(state
->entry_group
);
164 state
->entry_group
= NULL
;
172 adisk2
= avahi_string_list_add(adisk
, "sys=adVF=0x100");
173 if (adisk2
== NULL
) {
174 DBG_DEBUG("avahi_string_list_add failed: "
176 avahi_string_list_free(adisk
);
177 avahi_entry_group_free(state
->entry_group
);
178 state
->entry_group
= NULL
;
184 error
= avahi_entry_group_add_service_strlst(
185 state
->entry_group
, AVAHI_IF_UNSPEC
,
186 AVAHI_PROTO_UNSPEC
, 0, hostname
,
187 "_adisk._tcp", NULL
, NULL
, 0, adisk
);
188 avahi_string_list_free(adisk
);
190 if (error
!= AVAHI_OK
) {
191 DBG_DEBUG("avahi_entry_group_add_service_strlst "
192 "failed: %s\n", avahi_strerror(error
));
193 avahi_entry_group_free(state
->entry_group
);
194 state
->entry_group
= NULL
;
199 error
= avahi_entry_group_commit(state
->entry_group
);
200 if (error
!= AVAHI_OK
) {
201 DBG_DEBUG("avahi_entry_group_commit failed: %s\n",
202 avahi_strerror(error
));
203 avahi_entry_group_free(state
->entry_group
);
204 state
->entry_group
= NULL
;
209 case AVAHI_CLIENT_FAILURE
:
210 error
= avahi_client_errno(c
);
212 DBG_DEBUG("AVAHI_CLIENT_FAILURE: %s\n", avahi_strerror(error
));
214 if (error
!= AVAHI_ERR_DISCONNECTED
) {
217 avahi_client_free(c
);
218 state
->client
= avahi_client_new(state
->poll
, AVAHI_CLIENT_NO_FAIL
,
219 avahi_client_callback
, state
,
221 if (state
->client
== NULL
) {
222 DBG_DEBUG("avahi_client_new failed: %s\n",
223 avahi_strerror(error
));
227 case AVAHI_CLIENT_S_COLLISION
:
228 DBG_DEBUG("AVAHI_CLIENT_S_COLLISION\n");
230 case AVAHI_CLIENT_S_REGISTERING
:
231 DBG_DEBUG("AVAHI_CLIENT_S_REGISTERING\n");
233 case AVAHI_CLIENT_CONNECTING
:
234 DBG_DEBUG("AVAHI_CLIENT_CONNECTING\n");
239 void *avahi_start_register(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
242 struct avahi_state_struct
*state
;
245 avahi_allocator_ctx
= talloc_new(mem_ctx
);
246 if (avahi_allocator_ctx
== NULL
) {
249 avahi_set_allocator(&avahi_talloc_allocator
);
251 state
= talloc(mem_ctx
, struct avahi_state_struct
);
256 state
->poll
= tevent_avahi_poll(state
, ev
);
257 if (state
->poll
== NULL
) {
260 state
->client
= avahi_client_new(state
->poll
, AVAHI_CLIENT_NO_FAIL
,
261 avahi_client_callback
, state
,
263 if (state
->client
== NULL
) {
264 DBG_DEBUG("avahi_client_new failed: %s\n",
265 avahi_strerror(error
));