2 * Copyright (C) 2011-2012 Juho Vähä-Herttua
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
26 #define MAX_DEVICEID 18
27 #define MAX_SERVNAME 256
29 #define USE_LIBDL (defined(HAVE_LIBDL) && !defined(__APPLE__))
31 #if defined(WIN32) || USE_LIBDL
34 # if !defined(EFI32) && !defined(EFI64)
35 # define DNSSD_STDCALL __stdcall
37 # define DNSSD_STDCALL
41 # define DNSSD_STDCALL
44 typedef struct _DNSServiceRef_t
*DNSServiceRef
;
45 typedef union _TXTRecordRef_t
{ char PrivateData
[16]; char *ForceNaturalAlignment
; } TXTRecordRef
;
47 typedef uint32_t DNSServiceFlags
;
48 typedef int32_t DNSServiceErrorType
;
50 typedef void (DNSSD_STDCALL
*DNSServiceRegisterReply
)
53 DNSServiceFlags flags
,
54 DNSServiceErrorType errorCode
,
63 # define DNSSD_STDCALL
66 typedef DNSServiceErrorType (DNSSD_STDCALL
*DNSServiceRegister_t
)
69 DNSServiceFlags flags
,
70 uint32_t interfaceIndex
,
77 const void *txtRecord
,
78 DNSServiceRegisterReply callBack
,
81 typedef void (DNSSD_STDCALL
*DNSServiceRefDeallocate_t
)(DNSServiceRef sdRef
);
82 typedef void (DNSSD_STDCALL
*TXTRecordCreate_t
)
84 TXTRecordRef
*txtRecord
,
88 typedef void (DNSSD_STDCALL
*TXTRecordDeallocate_t
)(TXTRecordRef
*txtRecord
);
89 typedef DNSServiceErrorType (DNSSD_STDCALL
*TXTRecordSetValue_t
)
91 TXTRecordRef
*txtRecord
,
96 typedef uint16_t (DNSSD_STDCALL
*TXTRecordGetLength_t
)(const TXTRecordRef
*txtRecord
);
97 typedef const void * (DNSSD_STDCALL
*TXTRecordGetBytesPtr_t
)(const TXTRecordRef
*txtRecord
);
107 DNSServiceRegister_t DNSServiceRegister
;
108 DNSServiceRefDeallocate_t DNSServiceRefDeallocate
;
109 TXTRecordCreate_t TXTRecordCreate
;
110 TXTRecordSetValue_t TXTRecordSetValue
;
111 TXTRecordGetLength_t TXTRecordGetLength
;
112 TXTRecordGetBytesPtr_t TXTRecordGetBytesPtr
;
113 TXTRecordDeallocate_t TXTRecordDeallocate
;
115 DNSServiceRef raopService
;
116 DNSServiceRef airplayService
;
122 dnssd_init(int *error
)
126 if (error
) *error
= DNSSD_ERROR_NOERROR
;
128 dnssd
= calloc(1, sizeof(dnssd_t
));
130 if (error
) *error
= DNSSD_ERROR_OUTOFMEM
;
135 dnssd
->module
= LoadLibraryA("dnssd.dll");
136 if (!dnssd
->module
) {
137 if (error
) *error
= DNSSD_ERROR_LIBNOTFOUND
;
141 dnssd
->DNSServiceRegister
= (DNSServiceRegister_t
)GetProcAddress(dnssd
->module
, "DNSServiceRegister");
142 dnssd
->DNSServiceRefDeallocate
= (DNSServiceRefDeallocate_t
)GetProcAddress(dnssd
->module
, "DNSServiceRefDeallocate");
143 dnssd
->TXTRecordCreate
= (TXTRecordCreate_t
)GetProcAddress(dnssd
->module
, "TXTRecordCreate");
144 dnssd
->TXTRecordSetValue
= (TXTRecordSetValue_t
)GetProcAddress(dnssd
->module
, "TXTRecordSetValue");
145 dnssd
->TXTRecordGetLength
= (TXTRecordGetLength_t
)GetProcAddress(dnssd
->module
, "TXTRecordGetLength");
146 dnssd
->TXTRecordGetBytesPtr
= (TXTRecordGetBytesPtr_t
)GetProcAddress(dnssd
->module
, "TXTRecordGetBytesPtr");
147 dnssd
->TXTRecordDeallocate
= (TXTRecordDeallocate_t
)GetProcAddress(dnssd
->module
, "TXTRecordDeallocate");
149 if (!dnssd
->DNSServiceRegister
|| !dnssd
->DNSServiceRefDeallocate
|| !dnssd
->TXTRecordCreate
||
150 !dnssd
->TXTRecordSetValue
|| !dnssd
->TXTRecordGetLength
|| !dnssd
->TXTRecordGetBytesPtr
||
151 !dnssd
->TXTRecordDeallocate
) {
152 if (error
) *error
= DNSSD_ERROR_PROCNOTFOUND
;
153 FreeLibrary(dnssd
->module
);
158 dnssd
->module
= dlopen("libdns_sd.so", RTLD_LAZY
);
159 if (!dnssd
->module
) {
160 if (error
) *error
= DNSSD_ERROR_LIBNOTFOUND
;
164 dnssd
->DNSServiceRegister
= (DNSServiceRegister_t
)dlsym(dnssd
->module
, "DNSServiceRegister");
165 dnssd
->DNSServiceRefDeallocate
= (DNSServiceRefDeallocate_t
)dlsym(dnssd
->module
, "DNSServiceRefDeallocate");
166 dnssd
->TXTRecordCreate
= (TXTRecordCreate_t
)dlsym(dnssd
->module
, "TXTRecordCreate");
167 dnssd
->TXTRecordSetValue
= (TXTRecordSetValue_t
)dlsym(dnssd
->module
, "TXTRecordSetValue");
168 dnssd
->TXTRecordGetLength
= (TXTRecordGetLength_t
)dlsym(dnssd
->module
, "TXTRecordGetLength");
169 dnssd
->TXTRecordGetBytesPtr
= (TXTRecordGetBytesPtr_t
)dlsym(dnssd
->module
, "TXTRecordGetBytesPtr");
170 dnssd
->TXTRecordDeallocate
= (TXTRecordDeallocate_t
)dlsym(dnssd
->module
, "TXTRecordDeallocate");
172 if (!dnssd
->DNSServiceRegister
|| !dnssd
->DNSServiceRefDeallocate
|| !dnssd
->TXTRecordCreate
||
173 !dnssd
->TXTRecordSetValue
|| !dnssd
->TXTRecordGetLength
|| !dnssd
->TXTRecordGetBytesPtr
||
174 !dnssd
->TXTRecordDeallocate
) {
175 if (error
) *error
= DNSSD_ERROR_PROCNOTFOUND
;
176 dlclose(dnssd
->module
);
181 dnssd
->DNSServiceRegister
= &DNSServiceRegister
;
182 dnssd
->DNSServiceRefDeallocate
= &DNSServiceRefDeallocate
;
183 dnssd
->TXTRecordCreate
= &TXTRecordCreate
;
184 dnssd
->TXTRecordSetValue
= &TXTRecordSetValue
;
185 dnssd
->TXTRecordGetLength
= &TXTRecordGetLength
;
186 dnssd
->TXTRecordGetBytesPtr
= &TXTRecordGetBytesPtr
;
187 dnssd
->TXTRecordDeallocate
= &TXTRecordDeallocate
;
194 dnssd_destroy(dnssd_t
*dnssd
)
198 FreeLibrary(dnssd
->module
);
200 dlclose(dnssd
->module
);
207 dnssd_register_raop(dnssd_t
*dnssd
, const char *name
, unsigned short port
, const char *hwaddr
, int hwaddrlen
, int password
)
209 TXTRecordRef txtRecord
;
210 char servname
[MAX_SERVNAME
];
217 dnssd
->TXTRecordCreate(&txtRecord
, 0, NULL
);
218 dnssd
->TXTRecordSetValue(&txtRecord
, "txtvers", strlen(RAOP_TXTVERS
), RAOP_TXTVERS
);
219 dnssd
->TXTRecordSetValue(&txtRecord
, "ch", strlen(RAOP_CH
), RAOP_CH
);
220 dnssd
->TXTRecordSetValue(&txtRecord
, "cn", strlen(RAOP_CN
), RAOP_CN
);
221 dnssd
->TXTRecordSetValue(&txtRecord
, "et", strlen(RAOP_ET
), RAOP_ET
);
222 dnssd
->TXTRecordSetValue(&txtRecord
, "sv", strlen(RAOP_SV
), RAOP_SV
);
223 dnssd
->TXTRecordSetValue(&txtRecord
, "da", strlen(RAOP_DA
), RAOP_DA
);
224 dnssd
->TXTRecordSetValue(&txtRecord
, "sr", strlen(RAOP_SR
), RAOP_SR
);
225 dnssd
->TXTRecordSetValue(&txtRecord
, "ss", strlen(RAOP_SS
), RAOP_SS
);
227 dnssd
->TXTRecordSetValue(&txtRecord
, "pw", strlen("true"), "true");
229 dnssd
->TXTRecordSetValue(&txtRecord
, "pw", strlen("false"), "false");
231 dnssd
->TXTRecordSetValue(&txtRecord
, "vn", strlen(RAOP_VN
), RAOP_VN
);
232 dnssd
->TXTRecordSetValue(&txtRecord
, "tp", strlen(RAOP_TP
), RAOP_TP
);
233 dnssd
->TXTRecordSetValue(&txtRecord
, "md", strlen(RAOP_MD
), RAOP_MD
);
234 dnssd
->TXTRecordSetValue(&txtRecord
, "vs", strlen(GLOBAL_VERSION
), GLOBAL_VERSION
);
235 dnssd
->TXTRecordSetValue(&txtRecord
, "sm", strlen(RAOP_SM
), RAOP_SM
);
236 dnssd
->TXTRecordSetValue(&txtRecord
, "ek", strlen(RAOP_EK
), RAOP_EK
);
238 /* Convert hardware address to string */
239 ret
= utils_hwaddr_raop(servname
, sizeof(servname
), hwaddr
, hwaddrlen
);
241 /* FIXME: handle better */
245 /* Check that we have bytes for 'hw@name' format */
246 if (sizeof(servname
) < strlen(servname
)+1+strlen(name
)+1) {
247 /* FIXME: handle better */
251 strncat(servname
, "@", sizeof(servname
)-strlen(servname
)-1);
252 strncat(servname
, name
, sizeof(servname
)-strlen(servname
)-1);
254 /* Register the service */
255 dnssd
->DNSServiceRegister(&dnssd
->raopService
, 0, 0,
256 servname
, "_raop._tcp",
259 dnssd
->TXTRecordGetLength(&txtRecord
),
260 dnssd
->TXTRecordGetBytesPtr(&txtRecord
),
263 /* Deallocate TXT record */
264 dnssd
->TXTRecordDeallocate(&txtRecord
);
269 dnssd_register_airplay(dnssd_t
*dnssd
, const char *name
, unsigned short port
, const char *hwaddr
, int hwaddrlen
)
271 TXTRecordRef txtRecord
;
272 char deviceid
[3*MAX_HWADDR_LEN
];
280 /* Convert hardware address to string */
281 ret
= utils_hwaddr_airplay(deviceid
, sizeof(deviceid
), hwaddr
, hwaddrlen
);
283 /* FIXME: handle better */
287 features
[sizeof(features
)-1] = '\0';
288 snprintf(features
, sizeof(features
)-1, "0x%x", GLOBAL_FEATURES
);
290 dnssd
->TXTRecordCreate(&txtRecord
, 0, NULL
);
291 dnssd
->TXTRecordSetValue(&txtRecord
, "deviceid", strlen(deviceid
), deviceid
);
292 dnssd
->TXTRecordSetValue(&txtRecord
, "features", strlen(features
), features
);
293 dnssd
->TXTRecordSetValue(&txtRecord
, "model", strlen(GLOBAL_MODEL
), GLOBAL_MODEL
);
295 /* Register the service */
296 dnssd
->DNSServiceRegister(&dnssd
->airplayService
, 0, 0,
297 name
, "_airplay._tcp",
300 dnssd
->TXTRecordGetLength(&txtRecord
),
301 dnssd
->TXTRecordGetBytesPtr(&txtRecord
),
304 /* Deallocate TXT record */
305 dnssd
->TXTRecordDeallocate(&txtRecord
);
310 dnssd_unregister_raop(dnssd_t
*dnssd
)
314 if (!dnssd
->raopService
) {
318 dnssd
->DNSServiceRefDeallocate(dnssd
->raopService
);
319 dnssd
->raopService
= NULL
;
323 dnssd_unregister_airplay(dnssd_t
*dnssd
)
327 if (!dnssd
->airplayService
) {
331 dnssd
->DNSServiceRefDeallocate(dnssd
->airplayService
);
332 dnssd
->airplayService
= NULL
;