2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: ProxyResponder.c,v $
26 Revision 1.22 2003/08/14 02:19:55 cheshire
27 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
29 Revision 1.21 2003/08/12 19:56:26 cheshire
32 Revision 1.20 2003/07/23 00:00:04 cheshire
35 Revision 1.19 2003/07/15 01:55:16 cheshire
36 <rdar://problem/3315777> Need to implement service registration with subtypes
38 Revision 1.18 2003/07/02 21:19:58 cheshire
39 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
41 Revision 1.17 2003/05/26 03:21:29 cheshire
42 Tidy up address structure naming:
43 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
44 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
45 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
47 Revision 1.16 2003/05/26 03:01:28 cheshire
48 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
50 Revision 1.15 2003/05/06 00:00:50 cheshire
51 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
53 Revision 1.14 2003/04/25 01:45:57 cheshire
54 <rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
56 Revision 1.13 2003/04/18 22:46:12 cheshire
57 Fix mistake in 1.8 -- INADDR_NONE is 0xFFFFFFFF, not 0
59 Revision 1.12 2003/04/16 02:11:07 cheshire
60 Fixed mDNS_RegisterNoSuchService non-existance function so that it works again
62 Revision 1.11 2003/03/31 22:49:35 cheshire
67 #include <stdio.h> // For printf()
68 #include <stdlib.h> // For exit() etc.
69 #include <string.h> // For strlen() etc.
70 #include <unistd.h> // For select()
71 #include <errno.h> // For errno, EINTR
72 #include <arpa/inet.h> // For inet_addr()
73 #include <netinet/in.h> // For INADDR_NONE
74 #include <netdb.h> // For gethostbyname()
76 #include "mDNSClientAPI.h" // Defines the interface to the client layer above
77 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
78 #include "ExampleClientApp.h"
80 //*************************************************************************************************************
82 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
83 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
85 //*************************************************************************************************************
86 // Proxy Host Registration
91 domainlabel hostlabel
; // Conforms to standard DNS letter-digit-hyphen host name rules
92 AuthRecord RR_A
; // 'A' (address) record for our ".local" name
93 AuthRecord RR_PTR
; // PTR (reverse lookup) record
96 mDNSlocal
void HostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
98 ProxyHost
*f
= (ProxyHost
*)rr
->RecordContext
;
99 if (result
== mStatus_NoError
)
100 debugf("Host name successfully registered: %##s", &rr
->resrec
.name
);
103 debugf("Host name conflict for %##s", &rr
->resrec
.name
);
104 mDNS_Deregister(m
, &f
->RR_A
);
105 mDNS_Deregister(m
, &f
->RR_PTR
);
110 mDNSlocal mStatus
mDNS_RegisterProxyHost(mDNS
*m
, ProxyHost
*p
)
114 mDNS_SetupResourceRecord(&p
->RR_A
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, 60, kDNSRecordTypeUnique
, HostNameCallback
, p
);
115 mDNS_SetupResourceRecord(&p
->RR_PTR
, mDNSNULL
, mDNSInterface_Any
, kDNSType_PTR
, 60, kDNSRecordTypeKnownUnique
, HostNameCallback
, p
);
117 p
->RR_A
.resrec
.name
.c
[0] = 0;
118 AppendDomainLabel(&p
->RR_A
.resrec
.name
, &p
->hostlabel
);
119 AppendLiteralLabelString(&p
->RR_A
.resrec
.name
, "local");
121 mDNS_snprintf(buffer
, sizeof(buffer
), "%d.%d.%d.%d.in-addr.arpa.", p
->ip
.b
[3], p
->ip
.b
[2], p
->ip
.b
[1], p
->ip
.b
[0]);
122 MakeDomainNameFromDNSNameString(&p
->RR_PTR
.resrec
.name
, buffer
);
124 p
->RR_A
. resrec
.rdata
->u
.ip
= p
->ip
;
125 p
->RR_PTR
.resrec
.rdata
->u
.name
= p
->RR_A
.resrec
.name
;
127 mDNS_Register(m
, &p
->RR_A
);
128 mDNS_Register(m
, &p
->RR_PTR
);
130 debugf("Made Proxy Host Records for %##s", &p
->RR_A
.resrec
.name
);
132 return(mStatus_NoError
);
135 //*************************************************************************************************************
136 // Service Registration
138 // This sample ServiceCallback just calls mDNS_RenameAndReregisterService to automatically pick a new
139 // unique name for the service. For a device such as a printer, this may be appropriate.
140 // For a device with a user interface, and a screen, and a keyboard, the appropriate
141 // response may be to prompt the user and ask them to choose a new name for the service.
142 mDNSlocal
void ServiceCallback(mDNS
*const m
, ServiceRecordSet
*const sr
, mStatus result
)
146 case mStatus_NoError
: debugf("Callback: %##s Name Registered", &sr
->RR_SRV
.resrec
.name
); break;
147 case mStatus_NameConflict
: debugf("Callback: %##s Name Conflict", &sr
->RR_SRV
.resrec
.name
); break;
148 case mStatus_MemFree
: debugf("Callback: %##s Memory Free", &sr
->RR_SRV
.resrec
.name
); break;
149 default: debugf("Callback: %##s Unknown Result %d", &sr
->RR_SRV
.resrec
.name
, result
); break;
152 if (result
== mStatus_NoError
)
155 ConvertDomainNameToCString_unescaped(&sr
->RR_SRV
.resrec
.name
, buffer
);
156 printf("Service %s now registered and active\n", buffer
);
159 if (result
== mStatus_NameConflict
)
161 char buffer1
[256], buffer2
[256];
162 ConvertDomainNameToCString_unescaped(&sr
->RR_SRV
.resrec
.name
, buffer1
);
163 mDNS_RenameAndReregisterService(m
, sr
, mDNSNULL
);
164 ConvertDomainNameToCString_unescaped(&sr
->RR_SRV
.resrec
.name
, buffer2
);
165 printf("Name Conflict! %s renamed as %s\n", buffer1
, buffer2
);
169 // RegisterService() is a simple wrapper function which takes C string
170 // parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
171 mDNSlocal
void RegisterService(mDNS
*m
, ServiceRecordSet
*recordset
,
172 const char name
[], const char type
[], const char domain
[],
173 const domainname
*host
, mDNSu16 PortAsNumber
, int argc
, char **argv
)
178 unsigned char buffer
[1024], *bptr
= buffer
;
180 MakeDomainLabelFromLiteralString(&n
, name
);
181 MakeDomainNameFromDNSNameString(&t
, type
);
182 MakeDomainNameFromDNSNameString(&d
, domain
);
183 port
.b
[0] = (mDNSu8
)(PortAsNumber
>> 8);
184 port
.b
[1] = (mDNSu8
)(PortAsNumber
);
187 int len
= strlen(argv
[0]);
188 printf("STR: %s\n", argv
[0]);
190 strcpy(bptr
+1, argv
[0]);
196 mDNS_RegisterService(m
, recordset
,
197 &n
, &t
, &d
, // Name, type, domain
198 host
, port
, // Host and port
199 buffer
, bptr
-buffer
, // TXT data, length
200 mDNSNULL
, 0, // Subtypes
201 mDNSInterface_Any
, // Interace ID
202 ServiceCallback
, mDNSNULL
); // Callback and context
204 ConvertDomainNameToCString_unescaped(&recordset
->RR_SRV
.resrec
.name
, buffer
);
205 printf("Made Service Records for %s\n", buffer
);
208 //*************************************************************************************************************
209 // Service non-existence assertion
210 // (claiming a service name without actually providing a service at that name, to prevent anyone else using that name)
211 // This is useful to avoid confusion between similar services
212 // e.g. A printer that implements IPP printing service using the name "My Printer", but doesn't implement LPR service,
213 // should also claim the LPR service name "My Printer" to stop a different printer offering LPR service under the same name,
214 // since it would be confusing to users to have two equivalent services with the same name.
216 mDNSlocal
void NoSuchServiceCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
218 domainname
*proxyhostname
= (domainname
*)rr
->RecordContext
;
221 case mStatus_NoError
: debugf("Callback: %##s Name Registered", &rr
->resrec
.name
); break;
222 case mStatus_NameConflict
: debugf("Callback: %##s Name Conflict", &rr
->resrec
.name
); break;
223 case mStatus_MemFree
: debugf("Callback: %##s Memory Free", &rr
->resrec
.name
); break;
224 default: debugf("Callback: %##s Unknown Result %d", &rr
->resrec
.name
, result
); break;
227 if (result
== mStatus_NoError
)
230 ConvertDomainNameToCString_unescaped(&rr
->resrec
.name
, buffer
);
231 printf("Non-existence assertion %s now registered and active\n", buffer
);
234 if (result
== mStatus_NameConflict
)
238 char buffer1
[256], buffer2
[256];
239 ConvertDomainNameToCString_unescaped(&rr
->resrec
.name
, buffer1
);
240 DeconstructServiceName(&rr
->resrec
.name
, &n
, &t
, &d
);
241 IncrementLabelSuffix(&n
, mDNStrue
);
242 mDNS_RegisterNoSuchService(m
, rr
, &n
, &t
, &d
, proxyhostname
, mDNSInterface_Any
, NoSuchServiceCallback
, mDNSNULL
);
243 ConvertDomainNameToCString_unescaped(&rr
->resrec
.name
, buffer2
);
244 printf("Name Conflict! %s renamed as %s\n", buffer1
, buffer2
);
248 mDNSlocal
void RegisterNoSuchService(mDNS
*m
, AuthRecord
*const rr
, domainname
*proxyhostname
,
249 const char name
[], const char type
[], const char domain
[])
253 unsigned char buffer
[256];
254 MakeDomainLabelFromLiteralString(&n
, name
);
255 MakeDomainNameFromDNSNameString(&t
, type
);
256 MakeDomainNameFromDNSNameString(&d
, domain
);
257 mDNS_RegisterNoSuchService(m
, rr
, &n
, &t
, &d
, proxyhostname
, mDNSInterface_Any
, NoSuchServiceCallback
, proxyhostname
);
258 ConvertDomainNameToCString_unescaped(&rr
->resrec
.name
, buffer
);
259 printf("Made Non-existence Record for %s\n", buffer
);
262 //*************************************************************************************************************
265 mDNSexport
int main(int argc
, char **argv
)
269 if (argc
< 3) goto usage
;
271 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
272 mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
273 mDNS_Init_DontAdvertiseLocalAddresses
,
274 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
275 if (status
) { fprintf(stderr
, "Daemon start: mDNS_Init failed %ld\n", status
); return(status
); }
277 if (!strcmp(argv
[1], "-"))
279 domainname proxyhostname
;
280 AuthRecord proxyrecord
;
281 if (argc
< 5) goto usage
;
282 proxyhostname
.c
[0] = 0;
283 AppendLiteralLabelString(&proxyhostname
, argv
[2]);
284 AppendLiteralLabelString(&proxyhostname
, "local");
285 RegisterNoSuchService(&mDNSStorage
, &proxyrecord
, &proxyhostname
, argv
[3], argv
[4], "local.");
286 ExampleClientEventLoop(&mDNSStorage
);
287 mDNS_Close(&mDNSStorage
);
292 ServiceRecordSet proxyservice
;
294 proxyhost
.ip
.NotAnInteger
= inet_addr(argv
[1]);
295 if (proxyhost
.ip
.NotAnInteger
== INADDR_NONE
) // INADDR_NONE is 0xFFFFFFFF
297 struct hostent
*h
= gethostbyname(argv
[1]);
298 if (h
) proxyhost
.ip
.NotAnInteger
= *(long*)h
->h_addr
;
300 if (proxyhost
.ip
.NotAnInteger
== INADDR_NONE
) // INADDR_NONE is 0xFFFFFFFF
302 fprintf(stderr
, "%s is not valid host address\n", argv
[1]);
306 MakeDomainLabelFromLiteralString(&proxyhost
.hostlabel
, argv
[2]);
308 mDNS_RegisterProxyHost(&mDNSStorage
, &proxyhost
);
311 RegisterService(&mDNSStorage
, &proxyservice
, argv
[3], argv
[4], "local.",
312 &proxyhost
.RR_A
.resrec
.name
, atoi(argv
[5]), argc
-6, &argv
[6]);
314 ExampleClientEventLoop(&mDNSStorage
);
315 mDNS_Close(&mDNSStorage
);
321 fprintf(stderr
, "%s ip hostlabel [srvname srvtype port txt [txt ...]]\n", argv
[0]);
322 fprintf(stderr
, "ip Real IP address (or valid host name) of the host where the service actually resides\n");
323 fprintf(stderr
, "hostlabel First label of the dot-local host name to create for this host, e.g. \"foo\" for \"foo.local.\"\n");
324 fprintf(stderr
, "srvname Descriptive name of service, e.g. \"Stuart's Ink Jet Printer\"\n");
325 fprintf(stderr
, "srvtype IANA service type, e.g. \"_ipp._tcp\" or \"_ssh._tcp\", etc.\n");
326 fprintf(stderr
, "port Port number where the service resides (1-65535)\n");
327 fprintf(stderr
, "txt Additional name/value pairs specified in service definition, e.g. \"pdl=application/postscript\"\n");
328 fprintf(stderr
, "e.g. %s 169.254.12.34 thehost (just create a dot-local host name)\n", argv
[0]);
329 fprintf(stderr
, "or %s 169.254.12.34 thehost \"My Printer\" _printer._tcp. 515 rp=lpt1 pdl=application/postscript\n", argv
[0]);
330 fprintf(stderr
, "or %s - thehost \"My Printer\" _printer._tcp. (assertion of non-existence)\n", argv
[0]);