ef69178707817830f58508cce1218df499a448dc
[deb_shairplay.git] / src / lib / dnssd.m
1 /**
2 * Copyright (C) 2011-2012 Juho Vähä-Herttua
3 *
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.
8 *
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.
13 */
14
15 #include <stdlib.h>
16
17 #include "dnssd.h"
18 #include "dnssdint.h"
19 #include "global.h"
20 #include "utils.h"
21
22 #import <Foundation/Foundation.h>
23
24 #define MAX_SERVNAME 256
25
26 struct dnssd_s {
27 char hwaddr[MAX_HWADDR_LEN];
28 int hwaddrlen;
29
30 NSNetService *raopService;
31 NSNetService *airplayService;
32 };
33
34 dnssd_t *
35 dnssd_init(const char *hwaddr, int hwaddrlen, int *error)
36 {
37 dnssd_t *dnssd;
38
39 if (error) *error = DNSSD_ERROR_NOERROR;
40 if (hwaddrlen > MAX_HWADDR_LEN) {
41 if (error) *error = DNSSD_ERROR_HWADDRLEN;
42 return NULL;
43 }
44
45 dnssd = calloc(1, sizeof(dnssd_t));
46 if (!dnssd) {
47 if (error) *error = DNSSD_ERROR_OUTOFMEM;
48 return NULL;
49 }
50 memcpy(dnssd->hwaddr, hwaddr, hwaddrlen);
51 dnssd->hwaddrlen = hwaddrlen;
52
53 return dnssd;
54 }
55
56 void
57 dnssd_destroy(dnssd_t *dnssd)
58 {
59 free(dnssd);
60 }
61
62 int
63 dnssd_register_raop(dnssd_t *dnssd, const char *name, unsigned short port)
64 {
65 char hwaddrstr[MAX_SERVNAME];
66 NSString *serviceString;
67 NSMutableDictionary *txtDict;
68 NSData *txtData;
69 int ret;
70
71 assert(dnssd);
72
73 if (dnssd->raopService != nil) {
74 return -1;
75 }
76
77 /* Convert the hardware address to string */
78 ret = utils_hwaddr_raop(hwaddrstr, sizeof(hwaddrstr), dnssd->hwaddr, dnssd->hwaddrlen);
79 if (ret < 0) {
80 return -2;
81 }
82 serviceString = [NSString stringWithFormat:@"%s@%s", hwaddrstr, name];
83
84 txtDict = [NSMutableDictionary dictionaryWithCapacity:0];
85 [txtDict setValue:[NSString stringWithUTF8String:RAOP_TXTVERS] forKey:@"txtvers"];
86 [txtDict setValue:[NSString stringWithUTF8String:RAOP_CH] forKey:@"ch"];
87 [txtDict setValue:[NSString stringWithUTF8String:RAOP_CN] forKey:@"cn"];
88 [txtDict setValue:[NSString stringWithUTF8String:RAOP_ET] forKey:@"et"];
89 [txtDict setValue:[NSString stringWithUTF8String:RAOP_SV] forKey:@"sv"];
90 [txtDict setValue:[NSString stringWithUTF8String:RAOP_DA] forKey:@"da"];
91 [txtDict setValue:[NSString stringWithUTF8String:RAOP_SR] forKey:@"sr"];
92 [txtDict setValue:[NSString stringWithUTF8String:RAOP_SS] forKey:@"ss"];
93 [txtDict setValue:[NSString stringWithUTF8String:RAOP_PW] forKey:@"pw"];
94 [txtDict setValue:[NSString stringWithUTF8String:RAOP_VN] forKey:@"vn"];
95 [txtDict setValue:[NSString stringWithUTF8String:RAOP_TP] forKey:@"tp"];
96 [txtDict setValue:[NSString stringWithUTF8String:RAOP_MD] forKey:@"md"];
97 [txtDict setValue:[NSString stringWithUTF8String:GLOBAL_VERSION] forKey:@"vs"];
98 [txtDict setValue:[NSString stringWithUTF8String:RAOP_AM] forKey:@"am"];
99 [txtDict setValue:[NSString stringWithUTF8String:RAOP_SF] forKey:@"sf"];
100 txtData = [NSNetService dataFromTXTRecordDictionary:txtDict];
101
102 /* Create the service and publish it */
103 dnssd->raopService = [[NSNetService alloc] initWithDomain:@""
104 type:@"_raop._tcp"
105 name:serviceString
106 port:port];
107 [dnssd->raopService setTXTRecordData:txtData];
108 [dnssd->raopService publish];
109 return 1;
110 }
111
112 int
113 dnssd_register_airplay(dnssd_t *dnssd, const char *name, unsigned short port)
114 {
115 NSMutableDictionary *txtDict;
116 NSData *txtData;
117 char deviceid[3*MAX_HWADDR_LEN];
118 char features[16];
119 int ret;
120
121 assert(dnssd);
122
123 if (dnssd->airplayService != nil) {
124 return -1;
125 }
126
127 /* Convert hardware address to string */
128 ret = utils_hwaddr_airplay(deviceid, sizeof(deviceid), dnssd->hwaddr, dnssd->hwaddrlen);
129 if (ret < 0) {
130 return -2;
131 }
132
133 memset(features, 0, sizeof(features));
134 snprintf(features, sizeof(features)-1, "0x%x", GLOBAL_FEATURES);
135
136 txtDict = [NSMutableDictionary dictionaryWithCapacity:0];
137 [txtDict setValue:[NSString stringWithUTF8String:deviceid] forKey:@"deviceid"];
138 [txtDict setValue:[NSString stringWithUTF8String:features] forKey:@"features"];
139 [txtDict setValue:[NSString stringWithUTF8String:GLOBAL_MODEL] forKey:@"model"];
140 txtData = [NSNetService dataFromTXTRecordDictionary:txtDict];
141
142 /* Create the service and publish it */
143 dnssd->airplayService = [[NSNetService alloc] initWithDomain:@""
144 type:@"_airplay._tcp"
145 name:[NSString stringWithUTF8String:name]
146 port:port];
147 [dnssd->airplayService setTXTRecordData:txtData];
148 [dnssd->airplayService publish];
149 return 1;
150 }
151
152 void
153 dnssd_unregister_raop(dnssd_t *dnssd)
154 {
155 assert(dnssd);
156
157 if (dnssd->raopService == nil) {
158 return;
159 }
160
161 [dnssd->raopService stop];
162 [dnssd->raopService release];
163 dnssd->raopService = nil;
164 }
165
166 void
167 dnssd_unregister_airplay(dnssd_t *dnssd)
168 {
169 assert(dnssd);
170
171 if (dnssd->airplayService == nil) {
172 return;
173 }
174
175 [dnssd->airplayService stop];
176 [dnssd->airplayService release];
177 dnssd->airplayService = nil;
178 }