1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <stdio.h> // For printf()
19 #include <string.h> // For strlen() etc.
21 #include <Events.h> // For WaitNextEvent()
22 #include <SIOUX.h> // For SIOUXHandleOneEvent()
24 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
26 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
28 // These don't have to be globals, but their memory does need to remain valid for as
29 // long as the search is going on. They are declared as globals here for simplicity.
31 static mDNS_PlatformSupport p
;
32 static ServiceRecordSet p1
, p2
;
33 static AuthRecord availRec1
, availRec2
;
34 static Boolean availRec2Active
;
36 // This sample code just calls mDNS_RenameAndReregisterService to automatically pick a new
37 // unique name for the service. For a device such as a printer, this may be appropriate.
38 // For a device with a user interface, and a screen, and a keyboard, the appropriate
39 // response may be to prompt the user and ask them to choose a new name for the service.
40 mDNSlocal
void Callback(mDNS
*const m
, ServiceRecordSet
*const sr
, mStatus result
)
44 case mStatus_NoError
: debugf("Callback: %##s Name Registered", sr
->RR_SRV
.resrec
.name
.c
); break;
45 case mStatus_NameConflict
: debugf("Callback: %##s Name Conflict", sr
->RR_SRV
.resrec
.name
.c
); break;
46 case mStatus_MemFree
: debugf("Callback: %##s Memory Free", sr
->RR_SRV
.resrec
.name
.c
); break;
47 default: debugf("Callback: %##s Unknown Result %d", sr
->RR_SRV
.resrec
.name
.c
, result
); break;
50 if (result
== mStatus_NameConflict
) mDNS_RenameAndReregisterService(m
, sr
, mDNSNULL
);
53 // RegisterService() is a simple wrapper function which takes C string
54 // parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
55 mDNSlocal
void RegisterService(mDNS
*m
, ServiceRecordSet
*recordset
,
56 UInt16 PortAsNumber
, const char txtinfo
[],
57 const domainlabel
*const n
, const char type
[], const char domain
[])
61 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
64 MakeDomainNameFromDNSNameString(&t
, type
);
65 MakeDomainNameFromDNSNameString(&d
, domain
);
69 strncpy((char*)txtbuffer
+1, txtinfo
, sizeof(txtbuffer
)-1);
70 txtbuffer
[0] = (UInt8
)strlen(txtinfo
);
75 mDNS_RegisterService(m
, recordset
,
76 n
, &t
, &d
, // Name, type, domain
77 mDNSNULL
, mDNSOpaque16fromIntVal(PortAsNumber
),
78 txtbuffer
, (mDNSu16
)(1+txtbuffer
[0]), // TXT data, length
79 mDNSNULL
, 0, // Subtypes (none)
80 mDNSInterface_Any
, // Interface ID
81 Callback
, mDNSNULL
, 0); // Callback, context, flags
83 ConvertDomainNameToCString(recordset
->RR_SRV
.resrec
.name
, buffer
);
84 printf("Made Service Records for %s\n", buffer
);
87 // RegisterFakeServiceForTesting() simulates the effect of services being registered on
88 // dynamically-allocated port numbers. No real service exists on that port -- this is just for testing.
89 mDNSlocal
void RegisterFakeServiceForTesting(mDNS
*m
, ServiceRecordSet
*recordset
, const char txtinfo
[],
90 const char name
[], const char type
[], const char domain
[])
92 static UInt16 NextPort
= 0xF000;
94 MakeDomainLabelFromLiteralString(&n
, name
);
95 RegisterService(m
, recordset
, NextPort
++, txtinfo
, &n
, type
, domain
);
98 // Done once on startup, and then again every time our address changes
99 mDNSlocal OSStatus
mDNSResponderTestSetup(mDNS
*m
)
101 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
102 mDNSv4Addr ip
= m
->HostInterfaces
->ip
.ip
.v4
;
104 ConvertDomainNameToCString(&m
->MulticastHostname
, buffer
);
105 printf("Name %s\n", buffer
);
106 printf("IP %d.%d.%d.%d\n", ip
.b
[0], ip
.b
[1], ip
.b
[2], ip
.b
[3]);
109 printf("Registering Service Records\n");
110 // Create example printer discovery records
111 //static ServiceRecordSet p1, p2;
113 RegisterFakeServiceForTesting(m
, &p1
, "", "One", "_raop._tcp.", "local.");
114 RegisterFakeServiceForTesting(m
, &p2
, "", "Two", "_raop._tcp.", "local.");
119 mDNSlocal
void AvailCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
121 Boolean
*b
= (Boolean
*)rr
->RecordContext
;
123 // Signal that our record is now free for re-use
124 if (result
== mStatus_MemFree
) *b
= false;
127 mDNSlocal OSStatus
mDNSResponderSetAvail(mDNS
*m
, AuthRecord
*rr
, ServiceRecordSet
*sr
)
129 // 1. Initialize required fields of AuthRecord
130 // 2. Set name of subtype PTR record to our special subtype name denoting "available" instances
131 // 3. Set target of subtype PTR record to point to our SRV record (exactly the same as the main service PTR record)
132 // 4. And register it
133 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_Any
, kDNSType_PTR
, 2*3600, kDNSRecordTypeShared
, AvailCallback
, &availRec2Active
);
134 MakeDomainNameFromDNSNameString(rr
->resrec
.name
, "a._sub._raop._tcp.local.");
135 AssignDomainName(&rr
->resrec
.rdata
->u
.name
, sr
->RR_SRV
.resrec
.name
);
136 return(mDNS_Register(m
, rr
));
139 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
140 mDNSlocal Boolean
YieldSomeTime(UInt32 milliseconds
)
142 extern Boolean SIOUXQuitting
;
144 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
145 SIOUXHandleOneEvent(&e
);
146 return(SIOUXQuitting
);
152 Boolean DoneSetup
= false;
153 mDNSs32 nextAvail
, nextBusy
;
155 SIOUXSettings
.asktosaveonclose
= false;
156 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Responder";
158 printf("Multicast DNS Responder\n\n");
159 printf("This software reports errors using MacsBug breaks,\n");
160 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
161 printf("******************************************************************************\n");
163 err
= InitOpenTransport();
164 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
166 err
= mDNS_Init(&m
, &p
, mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
167 mDNS_Init_AdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
168 if (err
) return(err
);
170 while (!YieldSomeTime(35))
172 #if MDNS_ONLYSYSTEMTASK
173 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
174 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
175 extern void mDNSPlatformIdle(mDNS
*const m
);
176 mDNSPlatformIdle(&m
); // Only needed for debugging version
178 if (m
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
181 printf("\nListening for mDNS queries...\n");
182 mDNSResponderTestSetup(&m
);
183 mDNSResponderSetAvail(&m
, &availRec1
, &p1
);
184 availRec2Active
= false;
185 nextAvail
= mDNS_TimeNow(&m
) + mDNSPlatformOneSecond
* 10;
186 nextBusy
= mDNS_TimeNow(&m
) + mDNSPlatformOneSecond
* 15;
191 // We check availRec2.RecordType because we don't want to re-register this record
192 // if the previous mDNS_Deregister() has not yet completed
193 if (mDNS_TimeNow(&m
) - nextAvail
> 0 && !availRec2Active
)
195 printf("Setting Two now available\n");
196 availRec2Active
= true;
197 mDNSResponderSetAvail(&m
, &availRec2
, &p2
);
198 nextAvail
= nextBusy
+ mDNSPlatformOneSecond
* 10;
200 else if (mDNS_TimeNow(&m
) - nextBusy
> 0)
202 printf("Setting Two now busy\n");
203 mDNS_Deregister(&m
, &availRec2
);
204 nextBusy
= nextAvail
+ mDNSPlatformOneSecond
* 5;
209 if (p1
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &p1
);
210 if (p2
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &p2
);
211 if (availRec1
.resrec
.RecordType
) mDNS_Deregister(&m
, &availRec1
);
212 if (availRec2Active
) mDNS_Deregister(&m
, &availRec2
);