/* Can be used in either PA or Avahi mainloop context since the bits of u->core * that we access don't change after startup. */ static AvahiStringList* txt_record_server_data(pa_core *c, AvahiStringList *l) { char s[128]; char *t; pa_assert(c); l = avahi_string_list_add_pair(l, "server-version", PACKAGE_NAME" "PACKAGE_VERSION); t = pa_get_user_name_malloc(); l = avahi_string_list_add_pair(l, "user-name", t); pa_xfree(t); t = pa_machine_id(); l = avahi_string_list_add_pair(l, "machine-id", t); pa_xfree(t); t = pa_uname_string(); l = avahi_string_list_add_pair(l, "uname", t); pa_xfree(t); l = avahi_string_list_add_pair(l, "fqdn", pa_get_fqdn(s, sizeof(s))); l = avahi_string_list_add_printf(l, "cookie=0x%08x", c->cookie); return l; }
AvahiStringList* Avahi::PresencePublisher::prepare_txt_record () { AvahiStringList* result = NULL; result = avahi_string_list_add_printf (result, "presence=%s", details.get_presence ().c_str ()); result = avahi_string_list_add_printf (result, "status=%s", details.get_status ().c_str ()); result = avahi_string_list_add_printf (result, "software=%s %s", PACKAGE_NAME, PACKAGE_VERSION); return result; }
static AvahiStringList *add_magic_cookie( AvahiServer *s, AvahiStringList *strlst) { assert(s); if (!s->config.add_service_cookie) return strlst; if (avahi_string_list_find(strlst, AVAHI_SERVICE_COOKIE)) /* This string list already contains a magic cookie */ return strlst; return avahi_string_list_add_printf(strlst, AVAHI_SERVICE_COOKIE"=%u", s->local_service_cookie); }
static cupsd_txt_t /* O - TXT record */ dnssdBuildTxtRecord( cupsd_printer_t *p, /* I - Printer information */ int for_lpd) /* I - 1 = LPD, 0 = IPP */ { int i, /* Looping var */ count; /* Count of key/value pairs */ char admin_hostname[256], /* .local hostname for admin page */ adminurl_str[256], /* URL for the admin page */ type_str[32], /* Type to string buffer */ state_str[32], /* State to string buffer */ rp_str[1024], /* Queue name string buffer */ air_str[1024], /* auth-info-required string buffer */ *keyvalue[32][2]; /* Table of key/value pairs */ cupsd_txt_t txt; /* TXT record */ /* * Load up the key value pairs... */ count = 0; if (!for_lpd || (BrowseLocalProtocols & BROWSE_LPD)) { keyvalue[count ][0] = "txtvers"; keyvalue[count++][1] = "1"; keyvalue[count ][0] = "qtotal"; keyvalue[count++][1] = "1"; keyvalue[count ][0] = "rp"; keyvalue[count++][1] = rp_str; if (for_lpd) strlcpy(rp_str, p->name, sizeof(rp_str)); else snprintf(rp_str, sizeof(rp_str), "%s/%s", (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name); keyvalue[count ][0] = "ty"; keyvalue[count++][1] = p->make_model ? p->make_model : "Unknown"; if (strstr(DNSSDHostName, ".local")) strlcpy(admin_hostname, DNSSDHostName, sizeof(admin_hostname)); else snprintf(admin_hostname, sizeof(admin_hostname), "%s.local.", DNSSDHostName); httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str), # ifdef HAVE_SSL "https", # else "http", # endif /* HAVE_SSL */ NULL, admin_hostname, DNSSDPort, "/%s/%s", (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name); keyvalue[count ][0] = "adminurl"; keyvalue[count++][1] = adminurl_str; if (p->location) { keyvalue[count ][0] = "note"; keyvalue[count++][1] = p->location; } keyvalue[count ][0] = "priority"; keyvalue[count++][1] = for_lpd ? "100" : "0"; keyvalue[count ][0] = "product"; keyvalue[count++][1] = p->pc && p->pc->product ? p->pc->product : "Unknown"; keyvalue[count ][0] = "pdl"; keyvalue[count++][1] = p->pdl ? p->pdl : "application/postscript"; if (get_auth_info_required(p, air_str, sizeof(air_str))) { keyvalue[count ][0] = "air"; keyvalue[count++][1] = air_str; } keyvalue[count ][0] = "UUID"; keyvalue[count++][1] = p->uuid + 9; #ifdef HAVE_SSL keyvalue[count ][0] = "TLS"; keyvalue[count++][1] = "1.2"; #endif /* HAVE_SSL */ if (p->type & CUPS_PRINTER_FAX) { keyvalue[count ][0] = "Fax"; keyvalue[count++][1] = "T"; keyvalue[count ][0] = "rfo"; keyvalue[count++][1] = rp_str; } if (p->type & CUPS_PRINTER_COLOR) { keyvalue[count ][0] = "Color"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F"; } if (p->type & CUPS_PRINTER_DUPLEX) { keyvalue[count ][0] = "Duplex"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F"; } if (p->type & CUPS_PRINTER_STAPLE) { keyvalue[count ][0] = "Staple"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F"; } if (p->type & CUPS_PRINTER_COPIES) { keyvalue[count ][0] = "Copies"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F"; } if (p->type & CUPS_PRINTER_COLLATE) { keyvalue[count ][0] = "Collate"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F"; } if (p->type & CUPS_PRINTER_PUNCH) { keyvalue[count ][0] = "Punch"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F"; } if (p->type & CUPS_PRINTER_BIND) { keyvalue[count ][0] = "Bind"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F"; } if (p->type & CUPS_PRINTER_SORT) { keyvalue[count ][0] = "Sort"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F"; } if (p->type & CUPS_PRINTER_MFP) { keyvalue[count ][0] = "Scan"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F"; } snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE); snprintf(state_str, sizeof(state_str), "%d", p->state); keyvalue[count ][0] = "printer-state"; keyvalue[count++][1] = state_str; keyvalue[count ][0] = "printer-type"; keyvalue[count++][1] = type_str; } /* * Then pack them into a proper txt record... */ # ifdef HAVE_DNSSD TXTRecordCreate(&txt, 0, NULL); for (i = 0; i < count; i ++) { size_t len = strlen(keyvalue[i][1]); if (len < 256) TXTRecordSetValue(&txt, keyvalue[i][0], (uint8_t)len, keyvalue[i][1]); } # else for (i = 0, txt = NULL; i < count; i ++) txt = avahi_string_list_add_printf(txt, "%s=%s", keyvalue[i][0], keyvalue[i][1]); # endif /* HAVE_DNSSD */ return (txt); }
int dnssd_register(AvahiClient *c) { AvahiStringList *ipp_txt; /* DNS-SD IPP TXT record */ char temp[256]; /* Subtype service string */ char dnssd_name[1024]; char *dev_id = NULL; const char *make; /* I - Manufacturer */ const char *model; /* I - Model name */ const char *serial = NULL; const char *cmd; int pwgraster = 0, appleraster = 0, pclm = 0, pdf = 0, jpeg = 0; char formats[1024]; /* I - Supported formats */ char *ptr; int error; /* * Parse the device ID for MFG, MDL, and CMD */ dev_id = strdup(g_options.device_id); if ((ptr = strcasestr(dev_id, "MFG:")) == NULL) if ((ptr = strcasestr(dev_id, "MANUFACTURER:")) == NULL) { ERR("No manufacturer info in device ID"); free(dev_id); return -1; } make = strchr(ptr, ':') + 1; if ((ptr = strcasestr(dev_id, "MDL:")) == NULL) if ((ptr = strcasestr(dev_id, "MODEL:")) == NULL) { ERR("No model info in device ID"); free(dev_id); return -1; } model = strchr(ptr, ':') + 1; if ((ptr = strcasestr(dev_id, "SN:")) == NULL) if ((ptr = strcasestr(dev_id, "SERN:")) == NULL) { if ((ptr = strcasestr(dev_id, "SERIALNUMBER:")) == NULL) { NOTE("No serial number info in device ID"); } } if (ptr) serial = strchr(ptr, ':') + 1; if ((ptr = strcasestr(dev_id, "CMD:")) == NULL) if ((ptr = strcasestr(dev_id, "COMMAND SET:")) == NULL) { ERR("No page description language info in device ID"); free(dev_id); return -1; } cmd = strchr(ptr, ':') + 1; ptr = strchr(make, ';'); if (ptr) *ptr = '\0'; ptr = strchr(model, ';'); if (ptr) *ptr = '\0'; if (serial) { ptr = strchr(serial, ';'); if (ptr) *ptr = '\0'; } ptr = strchr(cmd, ';'); if (ptr) *ptr = '\0'; if ((ptr = strcasestr(cmd, "pwg")) != NULL && (ptr = strcasestr(ptr, "raster")) != NULL) pwgraster = 1; if (((ptr = strcasestr(cmd, "apple")) != NULL && (ptr = strcasestr(ptr, "raster")) != NULL) || ((ptr = strcasestr(cmd, "urf")) != NULL)) appleraster = 1; if ((ptr = strcasestr(cmd, "pclm")) != NULL) pclm = 1; if ((ptr = strcasestr(cmd, "pdf")) != NULL) pdf = 1; if ((ptr = strcasestr(cmd, "jpeg")) != NULL || (ptr = strcasestr(cmd, "jpg")) != NULL) jpeg = 1; snprintf(formats, sizeof(formats),"%s%s%s%s%s", (pdf ? "application/pdf," : ""), (pwgraster ? "image/pwg-raster," : ""), (appleraster ? "image/urf," : ""), (pclm ? "application/PCLm," : ""), (jpeg ? "image/jpeg," : "")); formats[strlen(formats) - 1] = '\0'; /* * Additional printer properties */ snprintf(temp, sizeof(temp), "http://localhost:%d/", g_options.real_port); if (serial) snprintf(dnssd_name, sizeof(dnssd_name), "%s [%s]", model, serial); else snprintf(dnssd_name, sizeof(dnssd_name), "%s", model); /* * Create the TXT record... */ ipp_txt = NULL; ipp_txt = avahi_string_list_add_printf(ipp_txt, "rp=ipp/print"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "ty=%s %s", make, model); if (strcasecmp(g_options.interface, "lo") == 0) ipp_txt = avahi_string_list_add_printf(ipp_txt, "adminurl=%s", temp); ipp_txt = avahi_string_list_add_printf(ipp_txt, "product=(%s)", model); ipp_txt = avahi_string_list_add_printf(ipp_txt, "pdl=%s", formats); ipp_txt = avahi_string_list_add_printf(ipp_txt, "Color=U"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "Duplex=U"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "usb_MFG=%s", make); ipp_txt = avahi_string_list_add_printf(ipp_txt, "usb_MDL=%s", model); if (appleraster) ipp_txt = avahi_string_list_add_printf(ipp_txt, "URF=CP1,IS1-5-7,MT1-2-3-4-5-6-8-9-10-11-12-13,RS300,SRGB24,V1.4,W8,DM1"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "priority=60"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "txtvers=1"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "qtotal=1"); free(dev_id); /* * Register _printer._tcp (LPD) with port 0 to reserve the service name... */ NOTE("Registering printer %s on interface %s for DNS-SD broadcasting ...", dnssd_name, g_options.interface); if (g_options.dnssd_data->ipp_ref == NULL) g_options.dnssd_data->ipp_ref = avahi_entry_group_new((c ? c : g_options.dnssd_data->DNSSDClient), dnssd_callback, NULL); if (g_options.dnssd_data->ipp_ref == NULL) { ERR("Could not establish Avahi entry group"); avahi_string_list_free(ipp_txt); return -1; } error = avahi_entry_group_add_service_strlst(g_options.dnssd_data->ipp_ref, (g_options.interface ? (int)if_nametoindex(g_options.interface) : AVAHI_IF_UNSPEC), AVAHI_PROTO_UNSPEC, 0, dnssd_name, "_printer._tcp", NULL, NULL, 0, NULL); if (error) ERR("Error registering %s as Unix printer (_printer._tcp): %d", dnssd_name, error); else NOTE("Registered %s as Unix printer (_printer._tcp).", dnssd_name); /* * Then register the _ipp._tcp (IPP)... */ error = avahi_entry_group_add_service_strlst(g_options.dnssd_data->ipp_ref, (g_options.interface ? (int)if_nametoindex(g_options.interface) : AVAHI_IF_UNSPEC), AVAHI_PROTO_UNSPEC, 0, dnssd_name, "_ipp._tcp", NULL, NULL, g_options.real_port, ipp_txt); if (error) ERR("Error registering %s as IPP printer (_ipp._tcp): %d", dnssd_name, error); else { NOTE("Registered %s as IPP printer (_ipp._tcp).", dnssd_name); error = avahi_entry_group_add_service_subtype(g_options.dnssd_data->ipp_ref, (g_options.interface ? (int)if_nametoindex(g_options.interface) : AVAHI_IF_UNSPEC), AVAHI_PROTO_UNSPEC, 0, dnssd_name, "_ipp._tcp", NULL, (appleraster && !pwgraster ? "_universal._sub._ipp._tcp" : "_print._sub._ipp._tcp")); if (error) ERR("Error registering subtype for IPP printer %s (_print._sub._ipp._tcp or _universal._sub._ipp._tcp): %d", dnssd_name, error); else NOTE("Registered subtype for IPP printer %s (_print._sub._ipp._tcp or _universal._sub._ipp._tcp).", dnssd_name); } /* * Finally _http.tcp (HTTP) for the web interface... */ error = avahi_entry_group_add_service_strlst(g_options.dnssd_data->ipp_ref, (g_options.interface ? (int)if_nametoindex(g_options.interface) : AVAHI_IF_UNSPEC), AVAHI_PROTO_UNSPEC, 0, dnssd_name, "_http._tcp", NULL, NULL, g_options.real_port, NULL); if (error) ERR("Error registering web interface of %s (_http._tcp): %d", dnssd_name, error); else { NOTE("Registered web interface of %s (_http._tcp).", dnssd_name); error = avahi_entry_group_add_service_subtype(g_options.dnssd_data->ipp_ref, (g_options.interface ? (int)if_nametoindex(g_options.interface) : AVAHI_IF_UNSPEC), AVAHI_PROTO_UNSPEC, 0, dnssd_name, "_http._tcp", NULL, "_printer._sub._http._tcp"); if (error) ERR("Error registering subtype for web interface of %s (_printer._sub._http._tcp): %d", dnssd_name, error); else NOTE("Registered subtype for web interface of %s (_printer._sub._http._tcp).", dnssd_name); } /* * Commit it... */ avahi_entry_group_commit(g_options.dnssd_data->ipp_ref); avahi_string_list_free(ipp_txt); return 0; }
/* * This function tries to register the AFP DNS * SRV service type. */ static void register_stuff(void) { uint port; const struct vol *volume; DSI *dsi; char name[MAXINSTANCENAMELEN+1]; AvahiStringList *strlist = NULL; AvahiStringList *strlist2 = NULL; char tmpname[256]; assert(ctx->client); if (!ctx->group) { if (!(ctx->group = avahi_entry_group_new(ctx->client, publish_reply, ctx))) { LOG(log_error, logtype_afpd, "Failed to create entry group: %s", avahi_strerror(avahi_client_errno(ctx->client))); goto fail; } } if (avahi_entry_group_is_empty(ctx->group)) { /* Register our service */ /* Build AFP volumes list */ int i = 0; strlist = avahi_string_list_add_printf(strlist, "sys=waMa=0,adVF=0x100"); for (volume = getvolumes(); volume; volume = volume->v_next) { if (convert_string(CH_UCS2, CH_UTF8_MAC, volume->v_u8mname, -1, tmpname, 255) <= 0) { LOG ( log_error, logtype_afpd, "Could not set Zeroconf volume name for TimeMachine"); goto fail; } if (volume->v_flags & AFPVOL_TM) { if (volume->v_uuid) { LOG(log_info, logtype_afpd, "Registering volume '%s' with UUID: '%s' for TimeMachine", volume->v_localname, volume->v_uuid); strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1,adVU=%s", i++, tmpname, volume->v_uuid); } else { LOG(log_warning, logtype_afpd, "Registering volume '%s' for TimeMachine. But UUID is invalid.", volume->v_localname); strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1", i++, tmpname); } } } /* AFP server */ for (dsi = ctx->obj->dsi; dsi; dsi = dsi->next) { port = getip_port((struct sockaddr *)&dsi->server); LOG(log_info, logtype_afpd, "hostname: %s", ctx->obj->options.hostname); if (convert_string(ctx->obj->options.unixcharset, CH_UTF8, ctx->obj->options.hostname, -1, name, MAXINSTANCENAMELEN) <= 0) { LOG(log_error, logtype_afpd, "Could not set Zeroconf instance name: %s", ctx->obj->options.hostname); goto fail; } if ((dsi->bonjourname = strdup(name)) == NULL) { LOG(log_error, logtype_afpd, "Could not set Zeroconf instance name"); goto fail; } LOG(log_info, logtype_afpd, "Registering server '%s' with Bonjour", dsi->bonjourname); if (avahi_entry_group_add_service(ctx->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, dsi->bonjourname, AFP_DNS_SERVICE_TYPE, NULL, NULL, port, NULL) < 0) { LOG(log_error, logtype_afpd, "Failed to add service: %s", avahi_strerror(avahi_client_errno(ctx->client))); goto fail; } if (i && avahi_entry_group_add_service_strlst(ctx->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, dsi->bonjourname, ADISK_SERVICE_TYPE, NULL, NULL, 9, /* discard */ strlist) < 0) { LOG(log_error, logtype_afpd, "Failed to add service: %s", avahi_strerror(avahi_client_errno(ctx->client))); goto fail; } /* if */ if (ctx->obj->options.mimicmodel) { strlist2 = avahi_string_list_add_printf(strlist2, "model=%s", ctx->obj->options.mimicmodel); if (avahi_entry_group_add_service_strlst(ctx->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, dsi->bonjourname, DEV_INFO_SERVICE_TYPE, NULL, NULL, 0, strlist2) < 0) { LOG(log_error, logtype_afpd, "Failed to add service: %s", avahi_strerror(avahi_client_errno(ctx->client))); goto fail; } } /* if (config->obj.options.mimicmodel) */ } /* for config*/ if (avahi_entry_group_commit(ctx->group) < 0) { LOG(log_error, logtype_afpd, "Failed to commit entry group: %s", avahi_strerror(avahi_client_errno(ctx->client))); goto fail; } } /* if avahi_entry_group_is_empty*/ return; fail: time(NULL); // avahi_threaded_poll_quit(ctx->threaded_poll); }
static void create_services(AvahiClient * c, Game * game) { gchar *hostname; gchar *servicename; AvahiStringList *sl; int ret; g_assert(c != NULL); /* If this is the first time we're called, let's create a new entry group */ if (!group) { if (! (group = avahi_entry_group_new(c, entry_group_callback, NULL))) { log_message(MSG_ERROR, _("Avahi error: %s, %s\n"), "avahi_entry_group_new() failed", avahi_strerror(avahi_client_errno(c))); avahi_glib_poll_free(glib_poll); return; } } sl = avahi_string_list_new(NULL, NULL); sl = avahi_string_list_add_printf(sl, "version=%s", PROTOCOL_VERSION); sl = avahi_string_list_add_printf(sl, "title=%s", game->params->title); /* Add the service for IPP */ hostname = game->hostname ? g_strdup(game->hostname) : get_my_hostname(); servicename = g_strdup_printf("%s [%s]", hostname, game->server_port); g_free(hostname); ret = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_NETWORK_PROTOCOL, 0, servicename, AVAHI_ANNOUNCE_NAME, NULL, NULL, atoi(game->server_port), sl); g_free(servicename); if (ret < 0) { gchar *msg = g_strdup_printf("Failed to add '%s' service", AVAHI_ANNOUNCE_NAME); log_message(MSG_ERROR, _("Avahi error: %s, %s\n"), msg, avahi_strerror(ret)); g_free(msg); avahi_string_list_free(sl); avahi_glib_poll_free(glib_poll); return; } /* Tell the server to register the service */ if ((ret = avahi_entry_group_commit(group)) < 0) { log_message(MSG_ERROR, _("Avahi error: %s, %s\n"), "Failed to commit entry_group", avahi_strerror(ret)); avahi_string_list_free(sl); avahi_glib_poll_free(glib_poll); return; } avahi_string_list_free(sl); return; }
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char *argv[]) { char *t, *v; uint8_t data[1024]; AvahiStringList *a = NULL, *b, *p; size_t size, n; int r; a = avahi_string_list_new("prefix", "a", "b", NULL); a = avahi_string_list_add(a, "start"); a = avahi_string_list_add(a, "foo=99"); a = avahi_string_list_add(a, "bar"); a = avahi_string_list_add(a, ""); a = avahi_string_list_add(a, ""); a = avahi_string_list_add(a, "quux"); a = avahi_string_list_add(a, ""); a = avahi_string_list_add_arbitrary(a, (const uint8_t*) "null\0null", 9); a = avahi_string_list_add_printf(a, "seven=%i %c", 7, 'x'); a = avahi_string_list_add_pair(a, "blubb", "blaa"); a = avahi_string_list_add_pair(a, "uxknurz", NULL); a = avahi_string_list_add_pair_arbitrary(a, "uxknurz2", (const uint8_t*) "blafasel\0oerks", 14); a = avahi_string_list_add(a, "end"); t = avahi_string_list_to_string(a); printf("--%s--\n", t); avahi_free(t); n = avahi_string_list_serialize(a, NULL, 0); size = avahi_string_list_serialize(a, data, sizeof(data)); assert(size == n); printf("%u\n", size); for (t = (char*) data, n = 0; n < size; n++, t++) { if (*t <= 32) printf("(%u)", *t); else printf("%c", *t); } printf("\n"); assert(avahi_string_list_parse(data, size, &b) == 0); printf("equal: %i\n", avahi_string_list_equal(a, b)); t = avahi_string_list_to_string(b); printf("--%s--\n", t); avahi_free(t); avahi_string_list_free(b); b = avahi_string_list_copy(a); assert(avahi_string_list_equal(a, b)); t = avahi_string_list_to_string(b); printf("--%s--\n", t); avahi_free(t); p = avahi_string_list_find(a, "seven"); assert(p); r = avahi_string_list_get_pair(p, &t, &v, NULL); assert(r >= 0); assert(t); assert(v); printf("<%s>=<%s>\n", t, v); avahi_free(t); avahi_free(v); p = avahi_string_list_find(a, "quux"); assert(p); r = avahi_string_list_get_pair(p, &t, &v, NULL); assert(r >= 0); assert(t); assert(!v); printf("<%s>=<%s>\n", t, v); avahi_free(t); avahi_free(v); avahi_string_list_free(a); avahi_string_list_free(b); n = avahi_string_list_serialize(NULL, NULL, 0); size = avahi_string_list_serialize(NULL, data, sizeof(data)); assert(size == 1); assert(size == n); assert(avahi_string_list_parse(data, size, &a) == 0); assert(!a); return 0; }
static int publish_service(struct service *s) { int r = -1; AvahiStringList *txt = NULL; const char *name = NULL, *t; pa_proplist *proplist = NULL; pa_sample_spec ss; pa_channel_map map; char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; enum service_subtype subtype; const char * const subtype_text[] = { [SUBTYPE_HARDWARE] = "hardware", [SUBTYPE_VIRTUAL] = "virtual", [SUBTYPE_MONITOR] = "monitor" }; pa_assert(s); if (!s->userdata->client || avahi_client_get_state(s->userdata->client) != AVAHI_CLIENT_S_RUNNING) return 0; if (!s->entry_group) { if (!(s->entry_group = avahi_entry_group_new(s->userdata->client, service_entry_group_callback, s))) { pa_log("avahi_entry_group_new(): %s", avahi_strerror(avahi_client_errno(s->userdata->client))); goto finish; } } else avahi_entry_group_reset(s->entry_group); txt = txt_record_server_data(s->userdata->core, txt); get_service_data(s, &ss, &map, &name, &proplist, &subtype); txt = avahi_string_list_add_pair(txt, "device", name); txt = avahi_string_list_add_printf(txt, "rate=%u", ss.rate); txt = avahi_string_list_add_printf(txt, "channels=%u", ss.channels); txt = avahi_string_list_add_pair(txt, "format", pa_sample_format_to_string(ss.format)); txt = avahi_string_list_add_pair(txt, "channel_map", pa_channel_map_snprint(cm, sizeof(cm), &map)); txt = avahi_string_list_add_pair(txt, "subtype", subtype_text[subtype]); if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_DESCRIPTION))) txt = avahi_string_list_add_pair(txt, "description", t); if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_ICON_NAME))) txt = avahi_string_list_add_pair(txt, "icon-name", t); if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_VENDOR_NAME))) txt = avahi_string_list_add_pair(txt, "vendor-name", t); if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_PRODUCT_NAME))) txt = avahi_string_list_add_pair(txt, "product-name", t); if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_CLASS))) txt = avahi_string_list_add_pair(txt, "class", t); if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_FORM_FACTOR))) txt = avahi_string_list_add_pair(txt, "form-factor", t); if (avahi_entry_group_add_service_strlst( s->entry_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, s->service_name, pa_sink_isinstance(s->device) ? SERVICE_TYPE_SINK : SERVICE_TYPE_SOURCE, NULL, NULL, compute_port(s->userdata), txt) < 0) { pa_log("avahi_entry_group_add_service_strlst(): %s", avahi_strerror(avahi_client_errno(s->userdata->client))); goto finish; } if (avahi_entry_group_add_service_subtype( s->entry_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, s->service_name, pa_sink_isinstance(s->device) ? SERVICE_TYPE_SINK : SERVICE_TYPE_SOURCE, NULL, pa_sink_isinstance(s->device) ? (subtype == SUBTYPE_HARDWARE ? SERVICE_SUBTYPE_SINK_HARDWARE : SERVICE_SUBTYPE_SINK_VIRTUAL) : (subtype == SUBTYPE_HARDWARE ? SERVICE_SUBTYPE_SOURCE_HARDWARE : (subtype == SUBTYPE_VIRTUAL ? SERVICE_SUBTYPE_SOURCE_VIRTUAL : SERVICE_SUBTYPE_SOURCE_MONITOR))) < 0) { pa_log("avahi_entry_group_add_service_subtype(): %s", avahi_strerror(avahi_client_errno(s->userdata->client))); goto finish; } if (pa_source_isinstance(s->device) && subtype != SUBTYPE_MONITOR) { if (avahi_entry_group_add_service_subtype( s->entry_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, s->service_name, SERVICE_TYPE_SOURCE, NULL, SERVICE_SUBTYPE_SOURCE_NON_MONITOR) < 0) { pa_log("avahi_entry_group_add_service_subtype(): %s", avahi_strerror(avahi_client_errno(s->userdata->client))); goto finish; } } if (avahi_entry_group_commit(s->entry_group) < 0) { pa_log("avahi_entry_group_commit(): %s", avahi_strerror(avahi_client_errno(s->userdata->client))); goto finish; } r = 0; pa_log_debug("Successfully created entry group for %s.", s->service_name); finish: /* Remove this service */ if (r < 0) service_free(s); avahi_string_list_free(txt); return r; }