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.
15 /* These defines allow us to compile on iOS */
17 # define __has_feature(x) 0
19 #ifndef __has_extension
20 # define __has_extension __has_feature
38 #define MAX_DEVICEID 18
39 #define MAX_SERVNAME 256
41 #define USE_LIBDL (defined(HAVE_LIBDL) && !defined(__APPLE__))
43 #if defined(WIN32) || USE_LIBDL
46 # if !defined(EFI32) && !defined(EFI64)
47 # define DNSSD_STDCALL __stdcall
49 # define DNSSD_STDCALL
53 # define DNSSD_STDCALL
56 typedef struct _DNSServiceRef_t
*DNSServiceRef
;
57 typedef union _TXTRecordRef_t
{ char PrivateData
[16]; char *ForceNaturalAlignment
; } TXTRecordRef
;
59 typedef uint32_t DNSServiceFlags
;
60 typedef int32_t DNSServiceErrorType
;
62 typedef void (DNSSD_STDCALL
*DNSServiceRegisterReply
)
65 DNSServiceFlags flags
,
66 DNSServiceErrorType errorCode
,
75 # define DNSSD_STDCALL
78 typedef DNSServiceErrorType (DNSSD_STDCALL
*DNSServiceRegister_t
)
81 DNSServiceFlags flags
,
82 uint32_t interfaceIndex
,
89 const void *txtRecord
,
90 DNSServiceRegisterReply callBack
,
93 typedef void (DNSSD_STDCALL
*DNSServiceRefDeallocate_t
)(DNSServiceRef sdRef
);
94 typedef void (DNSSD_STDCALL
*TXTRecordCreate_t
)
96 TXTRecordRef
*txtRecord
,
100 typedef void (DNSSD_STDCALL
*TXTRecordDeallocate_t
)(TXTRecordRef
*txtRecord
);
101 typedef DNSServiceErrorType (DNSSD_STDCALL
*TXTRecordSetValue_t
)
103 TXTRecordRef
*txtRecord
,
108 typedef uint16_t (DNSSD_STDCALL
*TXTRecordGetLength_t
)(const TXTRecordRef
*txtRecord
);
109 typedef const void * (DNSSD_STDCALL
*TXTRecordGetBytesPtr_t
)(const TXTRecordRef
*txtRecord
);
119 DNSServiceRegister_t DNSServiceRegister
;
120 DNSServiceRefDeallocate_t DNSServiceRefDeallocate
;
121 TXTRecordCreate_t TXTRecordCreate
;
122 TXTRecordSetValue_t TXTRecordSetValue
;
123 TXTRecordGetLength_t TXTRecordGetLength
;
124 TXTRecordGetBytesPtr_t TXTRecordGetBytesPtr
;
125 TXTRecordDeallocate_t TXTRecordDeallocate
;
127 DNSServiceRef raopService
;
128 DNSServiceRef airplayService
;
134 dnssd_init(int *error
)
138 if (error
) *error
= DNSSD_ERROR_NOERROR
;
140 dnssd
= calloc(1, sizeof(dnssd_t
));
142 if (error
) *error
= DNSSD_ERROR_OUTOFMEM
;
147 dnssd
->module
= LoadLibraryA("dnssd.dll");
148 if (!dnssd
->module
) {
149 if (error
) *error
= DNSSD_ERROR_LIBNOTFOUND
;
153 dnssd
->DNSServiceRegister
= (DNSServiceRegister_t
)GetProcAddress(dnssd
->module
, "DNSServiceRegister");
154 dnssd
->DNSServiceRefDeallocate
= (DNSServiceRefDeallocate_t
)GetProcAddress(dnssd
->module
, "DNSServiceRefDeallocate");
155 dnssd
->TXTRecordCreate
= (TXTRecordCreate_t
)GetProcAddress(dnssd
->module
, "TXTRecordCreate");
156 dnssd
->TXTRecordSetValue
= (TXTRecordSetValue_t
)GetProcAddress(dnssd
->module
, "TXTRecordSetValue");
157 dnssd
->TXTRecordGetLength
= (TXTRecordGetLength_t
)GetProcAddress(dnssd
->module
, "TXTRecordGetLength");
158 dnssd
->TXTRecordGetBytesPtr
= (TXTRecordGetBytesPtr_t
)GetProcAddress(dnssd
->module
, "TXTRecordGetBytesPtr");
159 dnssd
->TXTRecordDeallocate
= (TXTRecordDeallocate_t
)GetProcAddress(dnssd
->module
, "TXTRecordDeallocate");
161 if (!dnssd
->DNSServiceRegister
|| !dnssd
->DNSServiceRefDeallocate
|| !dnssd
->TXTRecordCreate
||
162 !dnssd
->TXTRecordSetValue
|| !dnssd
->TXTRecordGetLength
|| !dnssd
->TXTRecordGetBytesPtr
||
163 !dnssd
->TXTRecordDeallocate
) {
164 if (error
) *error
= DNSSD_ERROR_PROCNOTFOUND
;
165 FreeLibrary(dnssd
->module
);
170 dnssd
->module
= dlopen("libdns_sd.so", RTLD_LAZY
);
171 if (!dnssd
->module
) {
172 if (error
) *error
= DNSSD_ERROR_LIBNOTFOUND
;
176 dnssd
->DNSServiceRegister
= (DNSServiceRegister_t
)dlsym(dnssd
->module
, "DNSServiceRegister");
177 dnssd
->DNSServiceRefDeallocate
= (DNSServiceRefDeallocate_t
)dlsym(dnssd
->module
, "DNSServiceRefDeallocate");
178 dnssd
->TXTRecordCreate
= (TXTRecordCreate_t
)dlsym(dnssd
->module
, "TXTRecordCreate");
179 dnssd
->TXTRecordSetValue
= (TXTRecordSetValue_t
)dlsym(dnssd
->module
, "TXTRecordSetValue");
180 dnssd
->TXTRecordGetLength
= (TXTRecordGetLength_t
)dlsym(dnssd
->module
, "TXTRecordGetLength");
181 dnssd
->TXTRecordGetBytesPtr
= (TXTRecordGetBytesPtr_t
)dlsym(dnssd
->module
, "TXTRecordGetBytesPtr");
182 dnssd
->TXTRecordDeallocate
= (TXTRecordDeallocate_t
)dlsym(dnssd
->module
, "TXTRecordDeallocate");
184 if (!dnssd
->DNSServiceRegister
|| !dnssd
->DNSServiceRefDeallocate
|| !dnssd
->TXTRecordCreate
||
185 !dnssd
->TXTRecordSetValue
|| !dnssd
->TXTRecordGetLength
|| !dnssd
->TXTRecordGetBytesPtr
||
186 !dnssd
->TXTRecordDeallocate
) {
187 if (error
) *error
= DNSSD_ERROR_PROCNOTFOUND
;
188 dlclose(dnssd
->module
);
193 dnssd
->DNSServiceRegister
= &DNSServiceRegister
;
194 dnssd
->DNSServiceRefDeallocate
= &DNSServiceRefDeallocate
;
195 dnssd
->TXTRecordCreate
= &TXTRecordCreate
;
196 dnssd
->TXTRecordSetValue
= &TXTRecordSetValue
;
197 dnssd
->TXTRecordGetLength
= &TXTRecordGetLength
;
198 dnssd
->TXTRecordGetBytesPtr
= &TXTRecordGetBytesPtr
;
199 dnssd
->TXTRecordDeallocate
= &TXTRecordDeallocate
;
206 dnssd_destroy(dnssd_t
*dnssd
)
210 FreeLibrary(dnssd
->module
);
212 dlclose(dnssd
->module
);
219 dnssd_register_raop(dnssd_t
*dnssd
, const char *name
, unsigned short port
, const char *hwaddr
, int hwaddrlen
, int password
)
221 TXTRecordRef txtRecord
;
222 char servname
[MAX_SERVNAME
];
229 dnssd
->TXTRecordCreate(&txtRecord
, 0, NULL
);
230 dnssd
->TXTRecordSetValue(&txtRecord
, "txtvers", strlen(RAOP_TXTVERS
), RAOP_TXTVERS
);
231 dnssd
->TXTRecordSetValue(&txtRecord
, "ch", strlen(RAOP_CH
), RAOP_CH
);
232 dnssd
->TXTRecordSetValue(&txtRecord
, "cn", strlen(RAOP_CN
), RAOP_CN
);
233 dnssd
->TXTRecordSetValue(&txtRecord
, "et", strlen(RAOP_ET
), RAOP_ET
);
234 dnssd
->TXTRecordSetValue(&txtRecord
, "sv", strlen(RAOP_SV
), RAOP_SV
);
235 dnssd
->TXTRecordSetValue(&txtRecord
, "da", strlen(RAOP_DA
), RAOP_DA
);
236 dnssd
->TXTRecordSetValue(&txtRecord
, "sr", strlen(RAOP_SR
), RAOP_SR
);
237 dnssd
->TXTRecordSetValue(&txtRecord
, "ss", strlen(RAOP_SS
), RAOP_SS
);
239 dnssd
->TXTRecordSetValue(&txtRecord
, "pw", strlen("true"), "true");
241 dnssd
->TXTRecordSetValue(&txtRecord
, "pw", strlen("false"), "false");
243 dnssd
->TXTRecordSetValue(&txtRecord
, "vn", strlen(RAOP_VN
), RAOP_VN
);
244 dnssd
->TXTRecordSetValue(&txtRecord
, "tp", strlen(RAOP_TP
), RAOP_TP
);
245 dnssd
->TXTRecordSetValue(&txtRecord
, "md", strlen(RAOP_MD
), RAOP_MD
);
246 dnssd
->TXTRecordSetValue(&txtRecord
, "vs", strlen(GLOBAL_VERSION
), GLOBAL_VERSION
);
247 dnssd
->TXTRecordSetValue(&txtRecord
, "sm", strlen(RAOP_SM
), RAOP_SM
);
248 dnssd
->TXTRecordSetValue(&txtRecord
, "ek", strlen(RAOP_EK
), RAOP_EK
);
250 /* Convert hardware address to string */
251 ret
= utils_hwaddr_raop(servname
, sizeof(servname
), hwaddr
, hwaddrlen
);
253 /* FIXME: handle better */
257 /* Check that we have bytes for 'hw@name' format */
258 if (sizeof(servname
) < strlen(servname
)+1+strlen(name
)+1) {
259 /* FIXME: handle better */
263 strncat(servname
, "@", sizeof(servname
)-strlen(servname
)-1);
264 strncat(servname
, name
, sizeof(servname
)-strlen(servname
)-1);
266 /* Register the service */
267 dnssd
->DNSServiceRegister(&dnssd
->raopService
, 0, 0,
268 servname
, "_raop._tcp",
271 dnssd
->TXTRecordGetLength(&txtRecord
),
272 dnssd
->TXTRecordGetBytesPtr(&txtRecord
),
275 /* Deallocate TXT record */
276 dnssd
->TXTRecordDeallocate(&txtRecord
);
281 dnssd_register_airplay(dnssd_t
*dnssd
, const char *name
, unsigned short port
, const char *hwaddr
, int hwaddrlen
)
283 TXTRecordRef txtRecord
;
284 char deviceid
[3*MAX_HWADDR_LEN
];
292 /* Convert hardware address to string */
293 ret
= utils_hwaddr_airplay(deviceid
, sizeof(deviceid
), hwaddr
, hwaddrlen
);
295 /* FIXME: handle better */
299 features
[sizeof(features
)-1] = '\0';
300 snprintf(features
, sizeof(features
)-1, "0x%x", GLOBAL_FEATURES
);
302 dnssd
->TXTRecordCreate(&txtRecord
, 0, NULL
);
303 dnssd
->TXTRecordSetValue(&txtRecord
, "deviceid", strlen(deviceid
), deviceid
);
304 dnssd
->TXTRecordSetValue(&txtRecord
, "features", strlen(features
), features
);
305 dnssd
->TXTRecordSetValue(&txtRecord
, "model", strlen(GLOBAL_MODEL
), GLOBAL_MODEL
);
307 /* Register the service */
308 dnssd
->DNSServiceRegister(&dnssd
->airplayService
, 0, 0,
309 name
, "_airplay._tcp",
312 dnssd
->TXTRecordGetLength(&txtRecord
),
313 dnssd
->TXTRecordGetBytesPtr(&txtRecord
),
316 /* Deallocate TXT record */
317 dnssd
->TXTRecordDeallocate(&txtRecord
);
322 dnssd_unregister_raop(dnssd_t
*dnssd
)
326 if (!dnssd
->raopService
) {
330 dnssd
->DNSServiceRefDeallocate(dnssd
->raopService
);
331 dnssd
->raopService
= NULL
;
335 dnssd_unregister_airplay(dnssd_t
*dnssd
)
339 if (!dnssd
->airplayService
) {
343 dnssd
->DNSServiceRefDeallocate(dnssd
->airplayService
);
344 dnssd
->airplayService
= NULL
;