Ejemplo n.º 1
0
void Browser::updateService(const char *name,
                            const char *host_name,
                            const AvahiAddress *a,
                            uint16_t port,
                            AvahiStringList *txt) {
    // Find the service in our list
    Browser::Service s(name);
    auto it = std::lower_bound(services_.begin(), services_.end(), s);
    if (it == services_.end() || it->service_name != name) {
        return;
    }
    Browser::Service &svc = *it;
    auto index = createIndex(it - services_.begin(), 0);

    svc.host_name = host_name;
    char addr[AVAHI_ADDRESS_STR_MAX];
    avahi_address_snprint(addr, sizeof(addr), a);
    svc.address = addr;
    svc.port = port;
    svc.txt.clear();
    for (auto item = txt; item != nullptr; item = avahi_string_list_get_next(item)) {
        // TODO: this probably isn't actually UTF-8
        svc.txt.push_front(
            QString::fromUtf8(
                reinterpret_cast<const char*>(avahi_string_list_get_text(item)),
                avahi_string_list_get_size(item)));
    }
    Q_EMIT dataChanged(index, index);
}
/* TODO: Docs. Return value is only valid as long as @txt is. Reference: RFC 6763, §6. */
GHashTable *
_ostree_txt_records_parse (AvahiStringList *txt)
{
  AvahiStringList *l;
  g_autoptr(GHashTable) out = NULL;

  out = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_bytes_unref);

  for (l = txt; l != NULL; l = avahi_string_list_get_next (l))
    {
      const guint8 *txt;
      gsize txt_len;
      const gchar *key;
      const guint8 *value;
      gsize key_len, value_len;
      g_autofree gchar *key_allocated = NULL;
      g_autoptr(GBytes) value_allocated = NULL;

      txt = avahi_string_list_get_text (l);
      txt_len = avahi_string_list_get_size (l);

      if (!parse_txt_record (txt, txt_len, &key, &key_len, &value, &value_len))
        {
          g_debug ("Ignoring invalid TXT record of length %" G_GSIZE_FORMAT,
                   txt_len);
          continue;
        }

      key_allocated = g_ascii_strdown (key, key_len);

      if (g_hash_table_lookup_extended (out, key_allocated, NULL, NULL))
        {
          g_debug ("Ignoring duplicate TXT record ‘%s’", key_allocated);
          continue;
        }

      /* Distinguish between the case where the entire record is the key
       * (value == NULL) and the case where the record is the key + ‘=’ and the
       * value is empty (value != NULL && value_len == 0). */
      if (value != NULL)
        value_allocated = g_bytes_new_static (value, value_len);

      g_hash_table_insert (out, g_steal_pointer (&key_allocated), g_steal_pointer (&value_allocated));
    }

  return g_steal_pointer (&out);
}
Ejemplo n.º 3
0
static int
spawn_record_browser(AvahiClient *c, AvahiIfIndex intf, AvahiProtocol proto, const char *hostname, const char *domain,
		     uint16_t type, struct mdns_browser *mb, const char *name, uint16_t port, AvahiStringList *txt)
{
  AvahiRecordBrowser *rb;
  struct mdns_record_browser *rb_data;
  char *key;
  char *value;
  char *ptr;
  size_t len;
  int ret;

  rb_data = (struct mdns_record_browser *)malloc(sizeof(struct mdns_record_browser));
  if (!rb_data)
    {
      DPRINTF(E_LOG, L_MDNS, "Out of memory for record browser data\n");

      return -1;
    }

  memset(rb_data, 0, sizeof(struct mdns_record_browser));

  rb_data->mb = mb;
  rb_data->port = port;

  rb_data->name = strdup(name);
  if (!rb_data->name)
    {
      DPRINTF(E_LOG, L_MDNS, "Out of memory for service name\n");

      goto out_free_rb;
    }

  rb_data->domain = strdup(domain);
  if (!rb_data->domain)
    {
      DPRINTF(E_LOG, L_MDNS, "Out of memory for service domain\n");

      goto out_free_name;
    }

  while (txt)
    {
      len = avahi_string_list_get_size(txt);
      key = (char *)avahi_string_list_get_text(txt);

      ptr = memchr(key, '=', len);
      if (!ptr)
	{
	  value = "";
	  len = 0;
	}
      else
	{
	  *ptr = '\0';
	  value = ptr + 1;

	  len -= strlen(key) + 1;
	}

      ret = keyval_add_size(&rb_data->txt_kv, key, value, len);

      if (ptr)
	*ptr = '=';

      if (ret < 0)
	{
	  DPRINTF(E_LOG, L_MDNS, "Could not build TXT record keyval\n");

	  goto out_free_keyval;
	}

      txt = avahi_string_list_get_next(txt);
    }

  rb = NULL;
  switch (type)
    {
      case AVAHI_DNS_TYPE_A:
	rb = avahi_record_browser_new(c, intf, proto, hostname,
				      AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A, 0,
				      browse_record_callback_v4, rb_data);
	if (!rb)
	  DPRINTF(E_LOG, L_MDNS, "Could not create v4 record browser for host %s: %s\n",
		  hostname, avahi_strerror(avahi_client_errno(c)));
	break;

      case AVAHI_DNS_TYPE_AAAA:
	rb = avahi_record_browser_new(c, intf, proto, hostname,
				      AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA, 0,
				      browse_record_callback_v6, rb_data);
	if (!rb)
	  DPRINTF(E_LOG, L_MDNS, "Could not create v4 record browser for host %s: %s\n",
		  hostname, avahi_strerror(avahi_client_errno(c)));
	break;
    }

  if (!rb)
    goto out_free_keyval;

  return 0;

 out_free_keyval:
  keyval_clear(&rb_data->txt_kv);
  free(rb_data->domain);
 out_free_name:
  free(rb_data->name);
 out_free_rb:
  free(rb_data);

  return -1;
}
Ejemplo n.º 4
0
static void
browse_resolve_callback(AvahiServiceResolver *r, AvahiIfIndex intf, AvahiProtocol proto, AvahiResolverEvent event,
			const char *name, const char *type, const char *domain, const char *hostname, const AvahiAddress *addr,
			uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata)
{
  char address[AVAHI_ADDRESS_STR_MAX + IF_NAMESIZE + 2];
  char ifname[IF_NAMESIZE];
  struct keyval txt_kv;
  struct mdns_browser *mb;
  char *key;
  char *value;
  size_t len;
  int family;
  int ll;
  int ret;

  mb = (struct mdns_browser *)userdata;

  switch (event)
    {
      case AVAHI_RESOLVER_FAILURE:
	DPRINTF(E_LOG, L_MDNS, "Avahi Resolver failure: service '%s' type '%s': %s\n", name, type,
		avahi_strerror(avahi_client_errno(mdns_client)));
	break;

      case AVAHI_RESOLVER_FOUND:
	DPRINTF(E_DBG, L_MDNS, "Avahi Resolver: resolved service '%s' type '%s' proto %d\n", name, type, proto);

	// KK - if I reject 192.168.* my AirTunes get rejected.
	// How does avahi passes multiple IP addresses?
	// ll = is_link_local(addr);
	ll = 0;

	switch (proto)
	  {
	    case AVAHI_PROTO_INET:
		    avahi_record_browser_new()
	      if (ll)
		{
		  family = AF_UNSPEC;

		  DPRINTF(E_DBG, L_MDNS, "Discarding IPv4 LL address\n");
		  break;
		}

	      family = AF_INET;
	      avahi_address_snprint(address, sizeof(address), addr);
	      break;

	    case AVAHI_PROTO_INET6:
	      avahi_address_snprint(address, sizeof(address), addr);

	      if (ll)
		{
		  DPRINTF(E_DBG, L_MDNS, "Appending interface name to IPv6 LL address\n");

		  if (!if_indextoname(intf, ifname))
		    {
		      DPRINTF(E_LOG, L_MDNS, "Could not map interface index %d to a name\n", intf);

		      family = AF_UNSPEC;
		      break;
		    }

		  len = strlen(address);
		  ret = snprintf(address + len, sizeof(address) - len, "%%%s", ifname);
		  if ((ret < 0) || (ret > sizeof(address) - len))
		    {
		      DPRINTF(E_LOG, L_MDNS, "Buffer too short for scoped IPv6 LL\n");

		      family = AF_UNSPEC;
		      break;
		    }

		  DPRINTF(E_DBG, L_MDNS, "Scoped IPv6 LL: %s\n", address);
		}

	      family = AF_INET6;
	      break;

	    default:
	      DPRINTF(E_INFO, L_MDNS, "Avahi Resolver: unknown protocol %d\n", proto);

	      family = AF_UNSPEC;
	      break;
	  }

	if (family == AF_UNSPEC)
	  break;

	memset(&txt_kv, 0, sizeof(struct keyval));

	while (txt)
	  {
	    len = avahi_string_list_get_size(txt);
	    key = (char *)avahi_string_list_get_text(txt);

	    value = memchr(key, '=', len);
	    if (!value)
	      {
		value = "";
		len = 0;
	      }
	    else
	      {
		*value = '\0';
		value++;

		len -= strlen(key) + 1;
	      }

	    ret = keyval_add_size(&txt_kv, key, value, len);
	    if (ret < 0)
	      {
		DPRINTF(E_LOG, L_MDNS, "Could not build TXT record keyval\n");

		goto out_clear_txt_kv;
	      }

	    txt = avahi_string_list_get_next(txt);
	  }

	/* Execute callback (mb->cb) with all the data */
	mb->cb(name, type, domain, hostname, family, address, port, &txt_kv);

    out_clear_txt_kv:
	keyval_clear(&txt_kv);
	break;
    }

  avahi_service_resolver_free(r);
}
Ejemplo n.º 5
0
CAMLprim value stub_avahi_string_list_get_text(value l)
{
  CAMLparam1(l);
  CAMLreturn(caml_copy_string((const char *)avahi_string_list_get_text((AvahiStringList *)l)));
}