AvahiEntryGroup* avahi_entry_group_new (AvahiClient *client, AvahiEntryGroupCallback callback, void *userdata) { AvahiEntryGroup *group = NULL; DBusMessage *message = NULL, *reply = NULL; DBusError error; char *path; int state; assert(client); dbus_error_init (&error); if (!avahi_client_is_connected(client)) { avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); goto fail; } if (!(group = avahi_new(AvahiEntryGroup, 1))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } group->client = client; group->callback = callback; group->userdata = userdata; group->state_valid = 0; group->path = NULL; AVAHI_LLIST_PREPEND(AvahiEntryGroup, groups, client->groups, group); if (!(message = dbus_message_new_method_call( AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "EntryGroupNew"))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) || dbus_error_is_set (&error)) { avahi_client_set_errno (client, AVAHI_ERR_DBUS_ERROR); goto fail; } if (!dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) || dbus_error_is_set (&error)) { avahi_client_set_errno (client, AVAHI_ERR_DBUS_ERROR); goto fail; } if (!(group->path = avahi_strdup (path))) { /* FIXME: We don't remove the object on the server side */ avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } if ((state = retrieve_state(group)) < 0) { avahi_client_set_errno(client, state); goto fail; } avahi_entry_group_set_state(group, (AvahiEntryGroupState) state); dbus_message_unref(message); dbus_message_unref(reply); return group; fail: if (dbus_error_is_set(&error)) { avahi_client_set_dbus_error(client, &error); dbus_error_free(&error); } if (group) avahi_entry_group_free(group); if (message) dbus_message_unref(message); if (reply) dbus_message_unref(reply); return NULL; }
AvahiSServiceResolver *avahi_s_service_resolver_new( AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char *domain, AvahiProtocol aprotocol, AvahiLookupFlags flags, AvahiSServiceResolverCallback callback, void* userdata) { AvahiSServiceResolver *r; AvahiKey *k; char n[AVAHI_DOMAIN_NAME_MAX]; int ret; assert(server); assert(type); assert(callback); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(aprotocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !name || avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST|AVAHI_LOOKUP_NO_TXT|AVAHI_LOOKUP_NO_ADDRESS), AVAHI_ERR_INVALID_FLAGS); if (!domain) domain = server->domain_name; if ((ret = avahi_service_name_join(n, sizeof(n), name, type, domain)) < 0) { avahi_server_set_errno(server, ret); return NULL; } if (!(r = avahi_new(AvahiSServiceResolver, 1))) { avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); return NULL; } r->server = server; r->service_name = avahi_strdup(name); r->service_type = avahi_normalize_name_strdup(type); r->domain_name = avahi_normalize_name_strdup(domain); r->callback = callback; r->userdata = userdata; r->address_protocol = aprotocol; r->srv_record = r->txt_record = r->address_record = NULL; r->srv_flags = r->txt_flags = r->address_flags = 0; r->interface = interface; r->protocol = protocol; r->user_flags = flags; r->record_browser_a = r->record_browser_aaaa = r->record_browser_srv = r->record_browser_txt = NULL; r->time_event = NULL; AVAHI_LLIST_PREPEND(AvahiSServiceResolver, resolver, server->service_resolvers, r); k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV); r->record_browser_srv = avahi_s_record_browser_new(server, interface, protocol, k, flags & ~(AVAHI_LOOKUP_NO_TXT|AVAHI_LOOKUP_NO_ADDRESS), record_browser_callback, r); avahi_key_unref(k); if (!r->record_browser_srv) { avahi_s_service_resolver_free(r); return NULL; } if (!(flags & AVAHI_LOOKUP_NO_TXT)) { k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT); r->record_browser_txt = avahi_s_record_browser_new(server, interface, protocol, k, flags & ~(AVAHI_LOOKUP_NO_TXT|AVAHI_LOOKUP_NO_ADDRESS), record_browser_callback, r); avahi_key_unref(k); if (!r->record_browser_txt) { avahi_s_service_resolver_free(r); return NULL; } } start_timeout(r); return r; }
AvahiWideAreaLookup *avahi_wide_area_lookup_new( AvahiWideAreaLookupEngine *e, AvahiKey *key, AvahiWideAreaLookupCallback callback, void *userdata) { struct timeval tv; AvahiWideAreaLookup *l, *t; uint8_t *p; assert(e); assert(key); assert(callback); assert(userdata); l = avahi_new(AvahiWideAreaLookup, 1); l->engine = e; l->dead = 0; l->key = avahi_key_ref(key); l->cname_key = avahi_key_new_cname(l->key); l->callback = callback; l->userdata = userdata; /* If more than 65K wide area quries are issued simultaneously, * this will break. This should be limited by some higher level */ for (;; e->next_id++) if (!find_lookup(e, e->next_id)) break; /* This ID is not yet used. */ l->id = e->next_id++; /* We keep the packet around in case we need to repeat our query */ l->packet = avahi_dns_packet_new(0); avahi_dns_packet_set_field(l->packet, AVAHI_DNS_FIELD_ID, (uint16_t) l->id); avahi_dns_packet_set_field(l->packet, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, 0, 0)); p = avahi_dns_packet_append_key(l->packet, key, 0); assert(p); avahi_dns_packet_set_field(l->packet, AVAHI_DNS_FIELD_QDCOUNT, 1); if (send_to_dns_server(l, l->packet) < 0) { avahi_log_error(__FILE__": Failed to send packet."); avahi_dns_packet_free(l->packet); avahi_key_unref(l->key); if (l->cname_key) avahi_key_unref(l->cname_key); avahi_free(l); return NULL; } l->n_send = 1; l->time_event = avahi_time_event_new(e->server->time_event_queue, avahi_elapse_time(&tv, 500, 0), sender_timeout_callback, l); avahi_hashmap_insert(e->lookups_by_id, &l->id, l); t = avahi_hashmap_lookup(e->lookups_by_key, l->key); AVAHI_LLIST_PREPEND(AvahiWideAreaLookup, by_key, t, l); avahi_hashmap_replace(e->lookups_by_key, avahi_key_ref(l->key), t); AVAHI_LLIST_PREPEND(AvahiWideAreaLookup, lookups, e->lookups, l); return l; }
static int process_nlmsg(struct nlmsghdr *n) { assert(n); if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) { /* A link appeared or was removed */ struct ifinfomsg *ifi; ifi = NLMSG_DATA(n); if (ifi->ifi_family != AF_UNSPEC || (int) ifi->ifi_index != ifindex) return 0; if (n->nlmsg_type == RTM_DELLINK) { daemon_log(LOG_ERR, "Interface vanished."); return -1; } assert(n->nlmsg_type == RTM_NEWLINK); if ((ifi->ifi_flags & IFF_LOOPBACK) || (ifi->ifi_flags & IFF_NOARP) || ifi->ifi_type != ARPHRD_ETHER) { daemon_log(LOG_ERR, "Interface not suitable."); return -1; } } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) { /* An address was added or removed */ struct rtattr *a = NULL; struct ifaddrmsg *ifa; int l; uint32_t address = 0; Address *i; ifa = NLMSG_DATA(n); if (ifa->ifa_family != AF_INET || (int) ifa->ifa_index != ifindex) return 0; l = NLMSG_PAYLOAD(n, sizeof(*ifa)); a = IFLA_RTA(ifa); while(RTA_OK(a, l)) { switch(a->rta_type) { case IFA_LOCAL: case IFA_ADDRESS: assert(RTA_PAYLOAD(a) == 4); memcpy(&address, RTA_DATA(a), sizeof(uint32_t)); break; } a = RTA_NEXT(a, l); } if (!address || is_ll_address(address)) return 0; for (i = addresses; i; i = i->addresses_next) if (i->address == address) break; if (n->nlmsg_type == RTM_DELADDR && i) { AVAHI_LLIST_REMOVE(Address, addresses, addresses, i); avahi_free(i); } if (n->nlmsg_type == RTM_NEWADDR && !i) { i = avahi_new(Address, 1); i->address = address; AVAHI_LLIST_PREPEND(Address, addresses, addresses, i); } } return 0; }
AvahiSAddressResolver *avahi_s_address_resolver_new( AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, const AvahiAddress *address, AvahiLookupFlags flags, AvahiSAddressResolverCallback callback, void* userdata) { AvahiSAddressResolver *r; AvahiKey *k; char n[AVAHI_DOMAIN_NAME_MAX]; assert(server); assert(address); assert(callback); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, address->proto == AVAHI_PROTO_INET || address->proto == AVAHI_PROTO_INET6, AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST|AVAHI_LOOKUP_USE_LLMNR), AVAHI_ERR_INVALID_FLAGS); avahi_reverse_lookup_name(address, n, sizeof(n)); if (!(k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR))) { avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); return NULL; } if (!(r = avahi_new(AvahiSAddressResolver, 1))) { avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); avahi_key_unref(k); return NULL; } r->server = server; r->address = *address; r->callback = callback; r->userdata = userdata; r->ptr_record = NULL; r->interface = interface; r->protocol = protocol; r->flags = 0; r->retry_with_multicast = 0; r->retry_with_llmnr = 0; r->llmnr_has_record = 0; r->key = k; r->record_browser = NULL; AVAHI_LLIST_PREPEND(AvahiSAddressResolver, resolver, server->address_resolvers, r); r->time_event = NULL; if (!(flags & (AVAHI_LOOKUP_USE_MULTICAST|AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_LLMNR))) { if (!server->wide_area.wide_area_lookup_engine || !avahi_wide_area_has_servers(server->wide_area.wide_area_lookup_engine)) flags |= AVAHI_LOOKUP_USE_LLMNR; else { flags |= AVAHI_LOOKUP_USE_WIDE_AREA; r->retry_with_llmnr = 1; } r->retry_with_multicast = 1; } r->record_browser = avahi_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, r); if (!r->record_browser) { avahi_s_address_resolver_free(r); return NULL; } start_timeout(r); return r; }
AvahiServiceResolver * avahi_service_resolver_new( AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char *domain, AvahiProtocol aprotocol, AvahiLookupFlags flags, AvahiServiceResolverCallback callback, void *userdata) { DBusError error; AvahiServiceResolver *r = NULL; DBusMessage *message = NULL, *reply = NULL; int32_t i_interface, i_protocol, i_aprotocol; uint32_t u_flags; char *path; assert(client); assert(type); if (!domain) domain = ""; if (!name) name = ""; dbus_error_init (&error); if (!avahi_client_is_connected(client)) { avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); goto fail; } if (!(r = avahi_new(AvahiServiceResolver, 1))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } r->client = client; r->callback = callback; r->userdata = userdata; r->path = NULL; r->name = r->type = r->domain = NULL; r->interface = interface; r->protocol = protocol; AVAHI_LLIST_PREPEND(AvahiServiceResolver, service_resolvers, client->service_resolvers, r); if (name && name[0]) if (!(r->name = avahi_strdup(name))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } if (!(r->type = avahi_strdup(type))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } if (domain && domain[0]) if (!(r->domain = avahi_strdup(domain))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "ServiceResolverNew"))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } i_interface = (int32_t) interface; i_protocol = (int32_t) protocol; i_aprotocol = (int32_t) aprotocol; u_flags = (uint32_t) flags; if (!(dbus_message_append_args( message, DBUS_TYPE_INT32, &i_interface, DBUS_TYPE_INT32, &i_protocol, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &type, DBUS_TYPE_STRING, &domain, DBUS_TYPE_INT32, &i_aprotocol, DBUS_TYPE_UINT32, &u_flags, DBUS_TYPE_INVALID))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) || dbus_error_is_set(&error)) { avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); goto fail; } if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) || dbus_error_is_set(&error) || !path) { avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); goto fail; } if (!(r->path = avahi_strdup(path))) { /* FIXME: We don't remove the object on the server side */ avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } dbus_message_unref(message); dbus_message_unref(reply); return r; fail: if (dbus_error_is_set(&error)) { avahi_client_set_dbus_error(client, &error); dbus_error_free(&error); } if (r) avahi_service_resolver_free(r); if (message) dbus_message_unref(message); if (reply) dbus_message_unref(reply); return NULL; }
AvahiAddressResolver * avahi_address_resolver_new( AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, const AvahiAddress *a, AvahiLookupFlags flags, AvahiAddressResolverCallback callback, void *userdata) { DBusError error; AvahiAddressResolver *r = NULL; DBusMessage *message = NULL, *reply = NULL; int32_t i_interface, i_protocol; uint32_t u_flags; char *path; char addr[AVAHI_ADDRESS_STR_MAX], *address = addr; assert(client); assert(a); dbus_error_init (&error); if (!avahi_address_snprint (addr, sizeof(addr), a)) { avahi_client_set_errno(client, AVAHI_ERR_INVALID_ADDRESS); return NULL; } if (!avahi_client_is_connected(client)) { avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); goto fail; } if (!(r = avahi_new(AvahiAddressResolver, 1))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } r->client = client; r->callback = callback; r->userdata = userdata; r->path = NULL; r->interface = interface; r->protocol = protocol; r->address = *a; AVAHI_LLIST_PREPEND(AvahiAddressResolver, address_resolvers, client->address_resolvers, r); if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "AddressResolverNew"))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } i_interface = (int32_t) interface; i_protocol = (int32_t) protocol; u_flags = (uint32_t) flags; if (!(dbus_message_append_args( message, DBUS_TYPE_INT32, &i_interface, DBUS_TYPE_INT32, &i_protocol, DBUS_TYPE_STRING, &address, DBUS_TYPE_UINT32, &u_flags, DBUS_TYPE_INVALID))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) || dbus_error_is_set(&error)) { avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); goto fail; } if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) || dbus_error_is_set(&error) || !path) { avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); goto fail; } if (!(r->path = avahi_strdup(path))) { /* FIXME: We don't remove the object on the server side */ avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } dbus_message_unref(message); dbus_message_unref(reply); return r; fail: if (dbus_error_is_set(&error)) { avahi_client_set_dbus_error(client, &error); dbus_error_free(&error); } if (r) avahi_address_resolver_free(r); if (message) dbus_message_unref(message); if (reply) dbus_message_unref(reply); return NULL; }
AvahiSDomainBrowser *avahi_s_domain_browser_new( AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, const char *domain, AvahiDomainBrowserType type, AvahiLookupFlags flags, AvahiSDomainBrowserCallback callback, void* userdata) { static const char * const type_table[AVAHI_DOMAIN_BROWSER_MAX] = { "b", "db", "r", "dr", "lb" }; AvahiSDomainBrowser *b; AvahiKey *k = NULL; char n[AVAHI_DOMAIN_NAME_MAX]; int r; assert(server); assert(callback); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, type < AVAHI_DOMAIN_BROWSER_MAX, AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); if (!domain) domain = server->domain_name; if ((r = avahi_service_name_join(n, sizeof(n), type_table[type], "_dns-sd._udp", domain)) < 0) { avahi_server_set_errno(server, r); return NULL; } if (!(b = avahi_new(AvahiSDomainBrowser, 1))) { avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); return NULL; } b->ref = 1; b->server = server; b->callback = callback; b->userdata = userdata; b->record_browser = NULL; b->type = type; b->all_for_now_scheduled = 0; b->defer_event = NULL; AVAHI_LLIST_PREPEND(AvahiSDomainBrowser, browser, server->domain_browsers, b); if (!(k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR))) { avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); goto fail; } if (!(b->record_browser = avahi_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, b))) goto fail; avahi_key_unref(k); if (type == AVAHI_DOMAIN_BROWSER_BROWSE && b->server->config.browse_domains) b->defer_event = avahi_time_event_new(server->time_event_queue, NULL, defer_callback, b); return b; fail: if (k) avahi_key_unref(k); avahi_s_domain_browser_free(b); return NULL; }
static AvahiEntry * server_add_internal( AvahiServer *s, AvahiSEntryGroup *g, AvahiIfIndex interface, AvahiProtocol protocol, AvahiPublishFlags flags, AvahiRecord *r) { AvahiEntry *e; assert(s); assert(r); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, s->state != AVAHI_SERVER_FAILURE && s->state != AVAHI_SERVER_INVALID, AVAHI_ERR_BAD_STATE); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_FLAGS_VALID( flags, AVAHI_PUBLISH_NO_ANNOUNCE| AVAHI_PUBLISH_NO_PROBE| AVAHI_PUBLISH_UNIQUE| AVAHI_PUBLISH_ALLOW_MULTIPLE| AVAHI_PUBLISH_UPDATE| AVAHI_PUBLISH_USE_WIDE_AREA| AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_is_valid_domain_name(r->key->name), AVAHI_ERR_INVALID_HOST_NAME); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, r->ttl != 0, AVAHI_ERR_INVALID_TTL); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !avahi_key_is_pattern(r->key), AVAHI_ERR_IS_PATTERN); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_record_is_valid(r), AVAHI_ERR_INVALID_RECORD); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, r->key->clazz == AVAHI_DNS_CLASS_IN, AVAHI_ERR_INVALID_DNS_CLASS); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, (r->key->type != 0) && (r->key->type != AVAHI_DNS_TYPE_ANY) && (r->key->type != AVAHI_DNS_TYPE_OPT) && (r->key->type != AVAHI_DNS_TYPE_TKEY) && (r->key->type != AVAHI_DNS_TYPE_TSIG) && (r->key->type != AVAHI_DNS_TYPE_IXFR) && (r->key->type != AVAHI_DNS_TYPE_AXFR), AVAHI_ERR_INVALID_DNS_TYPE); transport_flags_from_domain(s, &flags, r->key->name); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !s->config.disable_publishing, AVAHI_ERR_NOT_PERMITTED); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !g || (g->state != AVAHI_ENTRY_GROUP_ESTABLISHED && g->state != AVAHI_ENTRY_GROUP_REGISTERING) || (flags & AVAHI_PUBLISH_UPDATE), AVAHI_ERR_BAD_STATE); if (flags & AVAHI_PUBLISH_UPDATE) { AvahiRecord *old_record; int is_first = 1; /* Update and existing record */ /* Find the first matching entry */ for (e = avahi_hashmap_lookup(s->entries_by_key, r->key); e; e = e->by_key_next) { if (!e->dead && e->group == g && e->interface == interface && e->protocol == protocol) break; is_first = 0; } /* Hmm, nothing found? */ if (!e) { avahi_server_set_errno(s, AVAHI_ERR_NOT_FOUND); return NULL; } /* Update the entry */ old_record = e->record; e->record = avahi_record_ref(r); e->flags = flags; /* Announce our changes when needed */ if (!avahi_record_equal_no_ttl(old_record, r) && (!g || g->state != AVAHI_ENTRY_GROUP_UNCOMMITED)) { /* Remove the old entry from all caches, if needed */ if (!(e->flags & AVAHI_PUBLISH_UNIQUE)) avahi_goodbye_entry(s, e, 1, 0); /* Reannounce our updated entry */ avahi_reannounce_entry(s, e); } /* If we were the first entry in the list, we need to update the key */ if (is_first) avahi_hashmap_replace(s->entries_by_key, e->record->key, e); avahi_record_unref(old_record); } else { AvahiEntry *t; /* Add a new record */ if (check_record_conflict(s, interface, protocol, r, flags) < 0) { avahi_server_set_errno(s, AVAHI_ERR_COLLISION); return NULL; } if (!(e = avahi_new(AvahiEntry, 1))) { avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); return NULL; } e->server = s; e->record = avahi_record_ref(r); e->group = g; e->interface = interface; e->protocol = protocol; e->flags = flags; e->dead = 0; AVAHI_LLIST_HEAD_INIT(AvahiAnnouncer, e->announcers); AVAHI_LLIST_PREPEND(AvahiEntry, entries, s->entries, e); /* Insert into hash table indexed by name */ t = avahi_hashmap_lookup(s->entries_by_key, e->record->key); AVAHI_LLIST_PREPEND(AvahiEntry, by_key, t, e); avahi_hashmap_replace(s->entries_by_key, e->record->key, t); /* Insert into group list */ if (g) AVAHI_LLIST_PREPEND(AvahiEntry, by_group, g->entries, e); avahi_announce_entry(s, e); } return e; }
AvahiIniFile* avahi_ini_file_load(const char *fname) { AvahiIniFile *f; FILE *fo; AvahiIniFileGroup *group = NULL; unsigned line; assert(fname); if (!(fo = fopen(fname, "r"))) { avahi_log_error("Failed to open file '%s': %s", fname, strerror(errno)); return NULL; } f = avahi_new(AvahiIniFile, 1); AVAHI_LLIST_HEAD_INIT(AvahiIniFileGroup, f->groups); f->n_groups = 0; line = 0; while (!feof(fo)) { char ln[256], *s, *e; AvahiIniFilePair *pair; if (!(fgets(ln, sizeof(ln), fo))) break; line++; s = ln + strspn(ln, " \t"); s[strcspn(s, "\r\n")] = 0; /* Skip comments and empty lines */ if (*s == '#' || *s == '%' || *s == 0) continue; if (*s == '[') { /* new group */ if (!(e = strchr(s, ']'))) { avahi_log_error("Unclosed group header in %s:%u: <%s>", fname, line, s); goto fail; } *e = 0; group = avahi_new(AvahiIniFileGroup, 1); group->name = avahi_strdup(s+1); group->n_pairs = 0; AVAHI_LLIST_HEAD_INIT(AvahiIniFilePair, group->pairs); AVAHI_LLIST_PREPEND(AvahiIniFileGroup, groups, f->groups, group); f->n_groups++; } else { /* Normal assignment */ if (!(e = strchr(s, '='))) { avahi_log_error("Missing assignment in %s:%u: <%s>", fname, line, s); goto fail; } if (!group) { avahi_log_error("Assignment outside group in %s:%u <%s>", fname, line, s); goto fail; } /* Split the key and the value */ *(e++) = 0; pair = avahi_new(AvahiIniFilePair, 1); pair->key = avahi_strdup(s); pair->value = avahi_strdup(e); AVAHI_LLIST_PREPEND(AvahiIniFilePair, pairs, group->pairs, pair); group->n_pairs++; } } fclose(fo); return f; fail: if (fo) fclose(fo); if (f) avahi_ini_file_free(f); return NULL; }
void avahi_cache_update(AvahiCache *c, AvahiRecord *r, int cache_flush, const AvahiAddress *a) { /* char *txt; */ assert(c); assert(r && r->ref >= 1); /* txt = avahi_record_to_string(r); */ if (r->ttl == 0) { /* This is a goodbye request */ AvahiCacheEntry *e; if ((e = lookup_record(c, r))) expire_in_one_second(c, e, AVAHI_CACHE_GOODBYE_FINAL); } else { AvahiCacheEntry *e = NULL, *first; struct timeval now; gettimeofday(&now, NULL); /* This is an update request */ if ((first = lookup_key(c, r->key))) { if (cache_flush) { /* For unique entries drop all entries older than one second */ for (e = first; e; e = e->by_key_next) { AvahiUsec t; t = avahi_timeval_diff(&now, &e->timestamp); if (t > 1000000) expire_in_one_second(c, e, AVAHI_CACHE_REPLACE_FINAL); } } /* Look for exactly the same entry */ for (e = first; e; e = e->by_key_next) if (avahi_record_equal_no_ttl(e->record, r)) break; } if (e) { /* avahi_log_debug("found matching cache entry"); */ /* We need to update the hash table key if we replace the * record */ if (e->by_key_prev == NULL) avahi_hashmap_replace(c->hashmap, r->key, e); /* Update the record */ avahi_record_unref(e->record); e->record = avahi_record_ref(r); /* avahi_log_debug("cache: updating %s", txt); */ } else { /* No entry found, therefore we create a new one */ /* avahi_log_debug("cache: couldn't find matching cache entry for %s", txt); */ if (c->n_entries >= AVAHI_CACHE_ENTRIES_MAX) return; if (!(e = avahi_new(AvahiCacheEntry, 1))) { avahi_log_error(__FILE__": Out of memory"); return; } e->cache = c; e->time_event = NULL; e->record = avahi_record_ref(r); /* Append to hash table */ AVAHI_LLIST_PREPEND(AvahiCacheEntry, by_key, first, e); avahi_hashmap_replace(c->hashmap, e->record->key, first); /* Append to linked list */ AVAHI_LLIST_PREPEND(AvahiCacheEntry, entry, c->entries, e); c->n_entries++; /* Notify subscribers */ avahi_multicast_lookup_engine_notify(c->server->mdns.multicast_lookup_engine, c->interface, e->record, AVAHI_BROWSER_NEW); } e->origin = *a; e->timestamp = now; next_expiry(c, e, 80); e->state = AVAHI_CACHE_VALID; e->cache_flush = cache_flush; } /* avahi_free(txt); */ }
/* handle address coming or going away */ static int rtm_dispatch_newdeladdr(struct rtm_dispinfo *di) { Address *ap; struct ifa_msghdr *ifam; struct sockaddr *sa; struct sockaddr_in *sin; int link_local; /* macro to skip to next RTA; has side-effects */ #define SKIPRTA(ifamsgp, rta, sa) \ do { \ if ((ifamsgp)->ifam_addrs & (rta)) \ (sa) = next_sa((sa)); \ } while (0) ifam = &((rtmunion_t *)di->di_buf)->ifam; assert(ifam->ifam_type == RTM_NEWADDR || ifam->ifam_type == RTM_DELADDR); daemon_log(LOG_DEBUG, "%s: %s for iface %d (%s)", __func__, ifam->ifam_type == RTM_NEWADDR ? "NEWADDR" : "DELADDR", ifam->ifam_index, (ifam->ifam_index == ifindex) ? "ours" : "not ours"); if (ifam->ifam_index != ifindex) return (0); if (!(ifam->ifam_addrs & RTA_IFA)) { daemon_log(LOG_ERR, "ifa msg has no RTA_IFA."); return (0); } /* skip over rtmsg padding correctly */ sa = (struct sockaddr *)(ifam + 1); SKIPRTA(ifam, RTA_DST, sa); SKIPRTA(ifam, RTA_GATEWAY, sa); SKIPRTA(ifam, RTA_NETMASK, sa); SKIPRTA(ifam, RTA_GENMASK, sa); SKIPRTA(ifam, RTA_IFP, sa); /* * sa now points to RTA_IFA sockaddr; we are only interested * in updates for routable addresses. */ if (sa->sa_family != AF_INET) { daemon_log(LOG_DEBUG, "%s: RTA_IFA family not AF_INET (=%d)", __func__, sa->sa_family); return (0); } sin = (struct sockaddr_in *)sa; link_local = IN_LINKLOCAL(ntohl(sin->sin_addr.s_addr)); daemon_log(LOG_DEBUG, "%s: %s for %s (%s)", __func__, ifam->ifam_type == RTM_NEWADDR ? "NEWADDR" : "DELADDR", inet_ntoa(sin->sin_addr), link_local ? "link local" : "routable"); if (link_local) return (0); for (ap = addresses; ap; ap = ap->addresses_next) { if (ap->address == sin->sin_addr.s_addr) break; } if (ifam->ifam_type == RTM_DELADDR && ap != NULL) { AVAHI_LLIST_REMOVE(Address, addresses, addresses, ap); avahi_free(ap); } if (ifam->ifam_type == RTM_NEWADDR && ap == NULL) { ap = avahi_new(Address, 1); ap->address = sin->sin_addr.s_addr; AVAHI_LLIST_PREPEND(Address, addresses, addresses, ap); } return (0); #undef SKIPRTA }
AvahiRecordBrowser* avahi_record_browser_new( AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, uint16_t clazz, uint16_t type, AvahiLookupFlags flags, AvahiRecordBrowserCallback callback, void *userdata) { AvahiRecordBrowser *b = NULL; DBusMessage *message = NULL, *reply = NULL; DBusError error; char *path; int32_t i_protocol, i_interface; uint32_t u_flags; assert(client); assert(name); assert(callback); dbus_error_init(&error); if (!avahi_client_is_connected(client)) { avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); goto fail; } if (!(b = avahi_new(AvahiRecordBrowser, 1))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } b->client = client; b->callback = callback; b->userdata = userdata; b->path = NULL; b->name = NULL; b->clazz = clazz; b->type = type; b->interface = interface; b->protocol = protocol; AVAHI_LLIST_PREPEND(AvahiRecordBrowser, record_browsers, client->record_browsers, b); if (!(b->name = avahi_strdup(name))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "RecordBrowserNew"))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } i_interface = (int32_t) interface; i_protocol = (int32_t) protocol; u_flags = (uint32_t) flags; if (!dbus_message_append_args( message, DBUS_TYPE_INT32, &i_interface, DBUS_TYPE_INT32, &i_protocol, DBUS_TYPE_STRING, &name, DBUS_TYPE_UINT16, &clazz, DBUS_TYPE_UINT16, &type, DBUS_TYPE_UINT32, &u_flags, DBUS_TYPE_INVALID)) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) || dbus_error_is_set(&error)) { avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); goto fail; } if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) || dbus_error_is_set(&error) || !path) { avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); goto fail; } if (!(b->path = avahi_strdup(path))) { /* FIXME: We don't remove the object on the server side */ avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } dbus_message_unref(message); dbus_message_unref(reply); return b; fail: if (dbus_error_is_set(&error)) { avahi_client_set_dbus_error(client, &error); dbus_error_free(&error); } if (b) avahi_record_browser_free(b); if (message) dbus_message_unref(message); if (reply) dbus_message_unref(reply); return NULL; }
AvahiDomainBrowser* avahi_domain_browser_new( AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, const char *domain, AvahiDomainBrowserType btype, AvahiLookupFlags flags, AvahiDomainBrowserCallback callback, void *userdata) { AvahiDomainBrowser *db = NULL; DBusMessage *message = NULL, *reply = NULL; DBusError error; char *path; int32_t i_interface, i_protocol, bt; uint32_t u_flags; assert(client); assert(callback); dbus_error_init (&error); if (!avahi_client_is_connected(client)) { avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); goto fail; } if (!domain) domain = ""; if (!(db = avahi_new (AvahiDomainBrowser, 1))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } db->ref = 1; db->client = client; db->callback = callback; db->userdata = userdata; db->path = NULL; db->interface = interface; db->protocol = protocol; db->static_browse_domains = NULL; db->defer_timeout = NULL; AVAHI_LLIST_PREPEND(AvahiDomainBrowser, domain_browsers, client->domain_browsers, db); if (!(client->flags & AVAHI_CLIENT_IGNORE_USER_CONFIG)) { parse_environment(db); parse_domain_file(db); } db->static_browse_domains = avahi_string_list_reverse(db->static_browse_domains); if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "DomainBrowserNew"))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } i_interface = (int32_t) interface; i_protocol = (int32_t) protocol; u_flags = (uint32_t) flags; bt = btype; if (!(dbus_message_append_args( message, DBUS_TYPE_INT32, &i_interface, DBUS_TYPE_INT32, &i_protocol, DBUS_TYPE_STRING, &domain, DBUS_TYPE_INT32, &bt, DBUS_TYPE_UINT32, &u_flags, DBUS_TYPE_INVALID))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) || dbus_error_is_set(&error)) { avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); goto fail; } if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) || dbus_error_is_set(&error) || !path) { avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); goto fail; } if (!(db->path = avahi_strdup(path))) { /* FIXME: We don't remove the object on the server side */ avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } if (db->static_browse_domains && btype == AVAHI_DOMAIN_BROWSER_BROWSE) { struct timeval tv = { 0, 0 }; if (!(db->defer_timeout = client->poll_api->timeout_new(client->poll_api, &tv, defer_timeout_callback, db))) { avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); goto fail; } } dbus_message_unref(message); dbus_message_unref(reply); return db; fail: if (dbus_error_is_set(&error)) { avahi_client_set_dbus_error(client, &error); dbus_error_free(&error); } if (db) avahi_domain_browser_free(db); if (message) dbus_message_unref(message); if (reply) dbus_message_unref(reply); return NULL; }