summaryrefslogtreecommitdiffstats
path: root/source3/smbd/avahi_register.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd/avahi_register.c')
-rw-r--r--source3/smbd/avahi_register.c300
1 files changed, 300 insertions, 0 deletions
diff --git a/source3/smbd/avahi_register.c b/source3/smbd/avahi_register.c
new file mode 100644
index 0000000..883c862
--- /dev/null
+++ b/source3/smbd/avahi_register.c
@@ -0,0 +1,300 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Register _smb._tcp with avahi
+ *
+ * Copyright (C) Volker Lendecke 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "smbd/smbd.h"
+
+#include <avahi-client/client.h>
+#include <avahi-client/publish.h>
+#include <avahi-common/error.h>
+#include <avahi-common/malloc.h>
+#include <avahi-common/strlst.h>
+
+struct avahi_state_struct {
+ struct AvahiPoll *poll;
+ AvahiClient *client;
+ AvahiEntryGroup *entry_group;
+ uint16_t port;
+};
+
+static void *avahi_allocator_ctx = NULL;
+
+static void * avahi_allocator_malloc(size_t size)
+{
+ return talloc_size(avahi_allocator_ctx, size);
+}
+
+static void avahi_allocator_free(void *p)
+{
+ TALLOC_FREE(p);
+}
+
+static void * avahi_allocator_realloc(void *p, size_t size)
+{
+ return talloc_realloc_size(avahi_allocator_ctx, p, size);
+}
+
+static void * avahi_allocator_calloc(size_t count, size_t size)
+{
+ void *p = talloc_array_size(avahi_allocator_ctx, size, count);
+ if (p) {
+ memset(p, 0, size * count);
+ }
+ return p;
+}
+
+static const struct AvahiAllocator avahi_talloc_allocator = {
+ &avahi_allocator_malloc,
+ &avahi_allocator_free,
+ &avahi_allocator_realloc,
+ &avahi_allocator_calloc
+};
+
+static void avahi_entry_group_callback(AvahiEntryGroup *g,
+ AvahiEntryGroupState status,
+ void *userdata)
+{
+ struct avahi_state_struct *state = talloc_get_type_abort(
+ userdata, struct avahi_state_struct);
+ int error;
+
+ switch (status) {
+ case AVAHI_ENTRY_GROUP_ESTABLISHED:
+ DBG_DEBUG("AVAHI_ENTRY_GROUP_ESTABLISHED\n");
+ break;
+ case AVAHI_ENTRY_GROUP_FAILURE:
+ error = avahi_client_errno(state->client);
+
+ DBG_DEBUG("AVAHI_ENTRY_GROUP_FAILURE: %s\n",
+ avahi_strerror(error));
+ break;
+ case AVAHI_ENTRY_GROUP_COLLISION:
+ DBG_DEBUG("AVAHI_ENTRY_GROUP_COLLISION\n");
+ break;
+ case AVAHI_ENTRY_GROUP_UNCOMMITED:
+ DBG_DEBUG("AVAHI_ENTRY_GROUP_UNCOMMITED\n");
+ break;
+ case AVAHI_ENTRY_GROUP_REGISTERING:
+ DBG_DEBUG("AVAHI_ENTRY_GROUP_REGISTERING\n");
+ break;
+ }
+}
+
+static void avahi_client_callback(AvahiClient *c, AvahiClientState status,
+ void *userdata)
+{
+ struct avahi_state_struct *state = talloc_get_type_abort(
+ userdata, struct avahi_state_struct);
+ int error;
+
+ switch (status) {
+ case AVAHI_CLIENT_S_RUNNING: {
+ int snum;
+ int num_services = lp_numservices();
+ size_t dk = 0;
+ AvahiStringList *adisk = NULL;
+ AvahiStringList *adisk2 = NULL;
+ AvahiStringList *dinfo = NULL;
+ const char *hostname = NULL;
+ enum mdns_name_values mdns_name = lp_mdns_name();
+ const char *model = NULL;
+
+ DBG_DEBUG("AVAHI_CLIENT_S_RUNNING\n");
+
+ switch (mdns_name) {
+ case MDNS_NAME_MDNS:
+ hostname = avahi_client_get_host_name(c);
+ break;
+ case MDNS_NAME_NETBIOS:
+ hostname = lp_netbios_name();
+ break;
+ default:
+ DBG_ERR("Unhandled mdns_name %d\n", mdns_name);
+ return;
+ }
+
+ state->entry_group = avahi_entry_group_new(
+ c, avahi_entry_group_callback, state);
+ if (state->entry_group == NULL) {
+ error = avahi_client_errno(c);
+ DBG_DEBUG("avahi_entry_group_new failed: %s\n",
+ avahi_strerror(error));
+ break;
+ }
+
+ error = avahi_entry_group_add_service(
+ state->entry_group, AVAHI_IF_UNSPEC,
+ AVAHI_PROTO_UNSPEC, 0, hostname,
+ "_smb._tcp", NULL, NULL, state->port, NULL);
+ if (error != AVAHI_OK) {
+ DBG_DEBUG("avahi_entry_group_add_service failed: %s\n",
+ avahi_strerror(error));
+ avahi_entry_group_free(state->entry_group);
+ state->entry_group = NULL;
+ break;
+ }
+
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_snum_ok(snum) &&
+ lp_parm_bool(snum, "fruit", "time machine", false))
+ {
+ adisk2 = avahi_string_list_add_printf(
+ adisk, "dk%zu=adVN=%s,adVF=0x82",
+ dk++, lp_const_servicename(snum));
+ if (adisk2 == NULL) {
+ DBG_DEBUG("avahi_string_list_add_printf"
+ "failed: returned NULL\n");
+ avahi_string_list_free(adisk);
+ avahi_entry_group_free(state->entry_group);
+ state->entry_group = NULL;
+ break;
+ }
+ adisk = adisk2;
+ adisk2 = NULL;
+ }
+ }
+ if (dk > 0) {
+ adisk2 = avahi_string_list_add(adisk, "sys=adVF=0x100");
+ if (adisk2 == NULL) {
+ DBG_DEBUG("avahi_string_list_add failed: "
+ "returned NULL\n");
+ avahi_string_list_free(adisk);
+ avahi_entry_group_free(state->entry_group);
+ state->entry_group = NULL;
+ break;
+ }
+ adisk = adisk2;
+ adisk2 = NULL;
+
+ error = avahi_entry_group_add_service_strlst(
+ state->entry_group, AVAHI_IF_UNSPEC,
+ AVAHI_PROTO_UNSPEC, 0, hostname,
+ "_adisk._tcp", NULL, NULL, 0, adisk);
+ avahi_string_list_free(adisk);
+ adisk = NULL;
+ if (error != AVAHI_OK) {
+ DBG_DEBUG("avahi_entry_group_add_service_strlst "
+ "failed: %s\n", avahi_strerror(error));
+ avahi_entry_group_free(state->entry_group);
+ state->entry_group = NULL;
+ break;
+ }
+ }
+
+ model = lp_parm_const_string(-1, "fruit", "model", "MacSamba");
+
+ dinfo = avahi_string_list_add_printf(NULL, "model=%s", model);
+ if (dinfo == NULL) {
+ DBG_DEBUG("avahi_string_list_add_printf"
+ "failed: returned NULL\n");
+ avahi_entry_group_free(state->entry_group);
+ state->entry_group = NULL;
+ break;
+ }
+
+ error = avahi_entry_group_add_service_strlst(
+ state->entry_group, AVAHI_IF_UNSPEC,
+ AVAHI_PROTO_UNSPEC, 0, hostname,
+ "_device-info._tcp", NULL, NULL, 0,
+ dinfo);
+ avahi_string_list_free(dinfo);
+ if (error != AVAHI_OK) {
+ DBG_DEBUG("avahi_entry_group_add_service failed: %s\n",
+ avahi_strerror(error));
+ avahi_entry_group_free(state->entry_group);
+ state->entry_group = NULL;
+ break;
+ }
+
+ error = avahi_entry_group_commit(state->entry_group);
+ if (error != AVAHI_OK) {
+ DBG_DEBUG("avahi_entry_group_commit failed: %s\n",
+ avahi_strerror(error));
+ avahi_entry_group_free(state->entry_group);
+ state->entry_group = NULL;
+ break;
+ }
+ break;
+ }
+ case AVAHI_CLIENT_FAILURE:
+ error = avahi_client_errno(c);
+
+ DBG_DEBUG("AVAHI_CLIENT_FAILURE: %s\n", avahi_strerror(error));
+
+ if (error != AVAHI_ERR_DISCONNECTED) {
+ break;
+ }
+ avahi_client_free(c);
+ state->client = avahi_client_new(state->poll, AVAHI_CLIENT_NO_FAIL,
+ avahi_client_callback, state,
+ &error);
+ if (state->client == NULL) {
+ DBG_DEBUG("avahi_client_new failed: %s\n",
+ avahi_strerror(error));
+ break;
+ }
+ break;
+ case AVAHI_CLIENT_S_COLLISION:
+ DBG_DEBUG("AVAHI_CLIENT_S_COLLISION\n");
+ break;
+ case AVAHI_CLIENT_S_REGISTERING:
+ DBG_DEBUG("AVAHI_CLIENT_S_REGISTERING\n");
+ break;
+ case AVAHI_CLIENT_CONNECTING:
+ DBG_DEBUG("AVAHI_CLIENT_CONNECTING\n");
+ break;
+ }
+}
+
+void *avahi_start_register(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ uint16_t port)
+{
+ struct avahi_state_struct *state;
+ int error;
+
+ avahi_allocator_ctx = talloc_new(mem_ctx);
+ if (avahi_allocator_ctx == NULL) {
+ return NULL;
+ }
+ avahi_set_allocator(&avahi_talloc_allocator);
+
+ state = talloc(mem_ctx, struct avahi_state_struct);
+ if (state == NULL) {
+ return state;
+ }
+ state->port = port;
+ state->poll = tevent_avahi_poll(state, ev);
+ if (state->poll == NULL) {
+ goto fail;
+ }
+ state->client = avahi_client_new(state->poll, AVAHI_CLIENT_NO_FAIL,
+ avahi_client_callback, state,
+ &error);
+ if (state->client == NULL) {
+ DBG_DEBUG("avahi_client_new failed: %s\n",
+ avahi_strerror(error));
+ goto fail;
+ }
+ return state;
+
+ fail:
+ TALLOC_FREE(state);
+ return NULL;
+}